/* * Copyright 2002-2017 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. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.cache; 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; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.concurrent.ConcurrentMapCache; import org.springframework.cache.concurrent.ConcurrentMapCacheManager; import org.springframework.cache.interceptor.AbstractCacheResolver; import org.springframework.cache.interceptor.CacheOperationInvocationContext; import org.springframework.cache.interceptor.CacheResolver; 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.*; /** * Tests to reproduce raised caching issues. * * @author Phillip Webb * @author Juergen Hoeller * @author Stephane Nicoll */ public class CacheReproTests { @Rule public final ExpectedException thrown = ExpectedException.none(); @Test public void spr11124MultipleAnnotations() throws Exception { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11124Config.class); Spr11124Service bean = context.getBean(Spr11124Service.class); bean.single(2); bean.single(2); bean.multiple(2); bean.multiple(2); context.close(); } @Test public void spr11249PrimitiveVarargs() throws Exception { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11249Config.class); Spr11249Service bean = context.getBean(Spr11249Service.class); Object result = bean.doSomething("op", 2, 3); assertSame(result, bean.doSomething("op", 2, 3)); context.close(); } @Test public void spr11592GetSimple() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11592Config.class); Spr11592Service bean = context.getBean(Spr11592Service.class); Cache cache = context.getBean("cache", Cache.class); String key = "1"; Object result = bean.getSimple("1"); 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 context.close(); } @Test public void spr11592GetNeverCache() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11592Config.class); Spr11592Service bean = context.getBean(Spr11592Service.class); Cache cache = context.getBean("cache", Cache.class); String key = "1"; Object result = bean.getNeverCache("1"); 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 context.close(); } @Test public void spr13081ConfigNoCacheNameIsRequired() { 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 assertEquals(result, cacheResolver.getCache("foo").get("foo").get()); } @Test public void spr13081ConfigFailIfCacheResolverReturnsNullCacheName() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr13081Config.class); Spr13081Service bean = context.getBean(Spr13081Service.class); this.thrown.expect(IllegalStateException.class); this.thrown.expectMessage(MyCacheResolver.class.getName()); bean.getSimple(null); } @Test public void spr14230AdaptsToOptional() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr14230Config.class); Spr14230Service bean = context.getBean(Spr14230Service.class); Cache cache = context.getBean(CacheManager.class).getCache("itemCache"); TestBean tb = new TestBean("tb1"); bean.insertItem(tb); assertSame(tb, bean.findById("tb1").get()); assertSame(tb, cache.get("tb1").get()); cache.clear(); TestBean tb2 = bean.findById("tb1").get(); assertNotSame(tb, tb2); assertSame(tb2, cache.get("tb1").get()); } @Test public void spr14853AdaptsToOptionalWithSync() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr14853Config.class); Spr14853Service bean = context.getBean(Spr14853Service.class); Cache cache = context.getBean(CacheManager.class).getCache("itemCache"); TestBean tb = new TestBean("tb1"); bean.insertItem(tb); assertSame(tb, bean.findById("tb1").get()); assertSame(tb, cache.get("tb1").get()); cache.clear(); TestBean tb2 = bean.findById("tb1").get(); assertNotSame(tb, tb2); assertSame(tb2, cache.get("tb1").get()); } @Test public void spr15271FindsOnInterfaceWithInterfaceProxy() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr15271ConfigA.class); Spr15271Interface bean = context.getBean(Spr15271Interface.class); Cache cache = context.getBean(CacheManager.class).getCache("itemCache"); TestBean tb = new TestBean("tb1"); bean.insertItem(tb); assertSame(tb, bean.findById("tb1").get()); assertSame(tb, cache.get("tb1").get()); } @Test public void spr15271FindsOnInterfaceWithCglibProxy() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr15271ConfigB.class); Spr15271Interface bean = context.getBean(Spr15271Interface.class); Cache cache = context.getBean(CacheManager.class).getCache("itemCache"); TestBean tb = new TestBean("tb1"); bean.insertItem(tb); assertSame(tb, bean.findById("tb1").get()); assertSame(tb, cache.get("tb1").get()); } @Configuration @EnableCaching public static class Spr11124Config { @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager(); } @Bean public Spr11124Service service() { return new Spr11124ServiceImpl(); } } public interface Spr11124Service { List<String> single(int id); List<String> multiple(int id); } public static class Spr11124ServiceImpl implements Spr11124Service { private int multipleCount = 0; @Override @Cacheable("smallCache") public List<String> single(int id) { if (this.multipleCount > 0) { fail("Called too many times"); } this.multipleCount++; return Collections.emptyList(); } @Override @Caching(cacheable = { @Cacheable(cacheNames = "bigCache", unless = "#result.size() < 4"), @Cacheable(cacheNames = "smallCache", unless = "#result.size() > 3")}) public List<String> multiple(int id) { if (this.multipleCount > 0) { fail("Called too many times"); } this.multipleCount++; return Collections.emptyList(); } } @Configuration @EnableCaching public static class Spr11249Config { @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager(); } @Bean public Spr11249Service service() { return new Spr11249Service(); } } public static class Spr11249Service { @Cacheable("smallCache") public Object doSomething(String name, int... values) { return new Object(); } } @Configuration @EnableCaching public static class Spr11592Config { @Bean public CacheManager cacheManager() { SimpleCacheManager cacheManager = new SimpleCacheManager(); cacheManager.setCaches(Collections.singletonList(cache())); return cacheManager; } @Bean public Cache cache() { Cache cache = new ConcurrentMapCache("cache"); return Mockito.spy(cache); } @Bean public Spr11592Service service() { return new Spr11592Service(); } } public static class Spr11592Service { @Cacheable("cache") public Object getSimple(String key) { return new Object(); } @Cacheable(cacheNames = "cache", condition = "false") public Object getNeverCache(String key) { return new Object(); } } @Configuration @EnableCaching public static class Spr13081Config extends CachingConfigurerSupport { @Bean @Override public CacheResolver cacheResolver() { return new MyCacheResolver(); } @Bean public Spr13081Service service() { return new Spr13081Service(); } } public static class MyCacheResolver extends AbstractCacheResolver { public MyCacheResolver() { super(new ConcurrentMapCacheManager()); } @Override protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> context) { String cacheName = (String) context.getArgs()[0]; if (cacheName != null) { return Collections.singleton(cacheName); } return null; } public Cache getCache(String name) { return getCacheManager().getCache(name); } } public static class Spr13081Service { @Cacheable public Object getSimple(String cacheName) { return new Object(); } } 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(); } } public static class Spr14853Service { @Cacheable(value = "itemCache", sync = true) 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 Spr14853Config { @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager(); } @Bean public Spr14853Service service() { return new Spr14853Service(); } } public interface Spr15271Interface { @Cacheable(value = "itemCache", sync = true) Optional<TestBean> findById(String id); @CachePut(cacheNames = "itemCache", key = "#item.name") TestBean insertItem(TestBean item); } public static class Spr15271Service implements Spr15271Interface { @Override public Optional<TestBean> findById(String id) { return Optional.of(new TestBean(id)); } @Override public TestBean insertItem(TestBean item) { return item; } } @Configuration @EnableCaching public static class Spr15271ConfigA { @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager(); } @Bean public Spr15271Interface service() { return new Spr15271Service(); } } @Configuration @EnableCaching(proxyTargetClass = true) public static class Spr15271ConfigB { @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager(); } @Bean public Spr15271Interface service() { return new Spr15271Service(); } } }