1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.cache.jcache.interceptor;
18
19 import java.lang.reflect.Method;
20 import java.util.Comparator;
21 import javax.cache.annotation.CacheDefaults;
22 import javax.cache.annotation.CacheKeyGenerator;
23 import javax.cache.annotation.CacheRemove;
24 import javax.cache.annotation.CacheRemoveAll;
25 import javax.cache.annotation.CacheResult;
26
27 import org.junit.Before;
28 import org.junit.Test;
29
30 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
31 import org.springframework.cache.interceptor.CacheResolver;
32 import org.springframework.cache.interceptor.KeyGenerator;
33 import org.springframework.cache.jcache.AbstractJCacheTests;
34 import org.springframework.cache.jcache.support.TestableCacheKeyGenerator;
35 import org.springframework.cache.jcache.support.TestableCacheResolver;
36 import org.springframework.cache.jcache.support.TestableCacheResolverFactory;
37 import org.springframework.util.Assert;
38 import org.springframework.util.ReflectionUtils;
39
40 import static org.junit.Assert.*;
41 import static org.mockito.BDDMockito.*;
42
43
44
45
46 public class AnnotationCacheOperationSourceTests extends AbstractJCacheTests {
47
48 private final DefaultJCacheOperationSource source = new DefaultJCacheOperationSource();
49
50 private final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
51
52
53 @Before
54 public void setUp() {
55 source.setCacheResolver(defaultCacheResolver);
56 source.setExceptionCacheResolver(defaultExceptionCacheResolver);
57 source.setKeyGenerator(defaultKeyGenerator);
58 source.setBeanFactory(beanFactory);
59 source.afterPropertiesSet();
60 }
61
62
63 @Test
64 public void cache() {
65 CacheResultOperation op = getDefaultCacheOperation(CacheResultOperation.class, String.class);
66 assertDefaults(op);
67 assertNull("Exception caching not enabled so resolver should not be set", op.getExceptionCacheResolver());
68 }
69
70 @Test
71 public void cacheWithException() {
72 CacheResultOperation op = getDefaultCacheOperation(CacheResultOperation.class, String.class, boolean.class);
73 assertDefaults(op);
74 assertEquals(defaultExceptionCacheResolver, op.getExceptionCacheResolver());
75 assertEquals("exception", op.getExceptionCacheName());
76 }
77
78 @Test
79 public void put() {
80 CachePutOperation op = getDefaultCacheOperation(CachePutOperation.class, String.class, Object.class);
81 assertDefaults(op);
82 }
83
84 @Test
85 public void remove() {
86 CacheRemoveOperation op = getDefaultCacheOperation(CacheRemoveOperation.class, String.class);
87 assertDefaults(op);
88 }
89
90 @Test
91 public void removeAll() {
92 CacheRemoveAllOperation op = getDefaultCacheOperation(CacheRemoveAllOperation.class);
93 assertEquals(defaultCacheResolver, op.getCacheResolver());
94 }
95
96 @Test
97 public void noAnnotation() {
98 assertNull(getCacheOperation(AnnotatedJCacheableService.class, name.getMethodName()));
99 }
100
101 @Test
102 public void multiAnnotations() {
103 thrown.expect(IllegalStateException.class);
104 getCacheOperation(InvalidCases.class, name.getMethodName());
105 }
106
107 @Test
108 public void defaultCacheNameWithCandidate() {
109 Method method = ReflectionUtils.findMethod(Object.class, "toString");
110 assertEquals("foo", source.determineCacheName(method, null, "foo"));
111 }
112
113 @Test
114 public void defaultCacheNameWithDefaults() {
115 Method method = ReflectionUtils.findMethod(Object.class, "toString");
116 CacheDefaults mock = mock(CacheDefaults.class);
117 given(mock.cacheName()).willReturn("");
118 assertEquals("java.lang.Object.toString()", source.determineCacheName(method, mock, ""));
119 }
120
121 @Test
122 public void defaultCacheNameNoDefaults() {
123 Method method = ReflectionUtils.findMethod(Object.class, "toString");
124 assertEquals("java.lang.Object.toString()", source.determineCacheName(method, null, ""));
125 }
126
127 @Test
128 public void defaultCacheNameWithParameters() {
129 Method method = ReflectionUtils.findMethod(Comparator.class, "compare", Object.class, Object.class);
130 assertEquals("java.util.Comparator.compare(java.lang.Object,java.lang.Object)",
131 source.determineCacheName(method, null, ""));
132 }
133
134 @Test
135 public void customCacheResolver() {
136 CacheResultOperation operation =
137 getCacheOperation(CacheResultOperation.class, CustomService.class, name.getMethodName(), Long.class);
138 assertJCacheResolver(operation.getCacheResolver(), TestableCacheResolver.class);
139 assertJCacheResolver(operation.getExceptionCacheResolver(), null);
140 assertEquals(KeyGeneratorAdapter.class, operation.getKeyGenerator().getClass());
141 assertEquals(defaultKeyGenerator, ((KeyGeneratorAdapter) operation.getKeyGenerator()).getTarget());
142 }
143
144 @Test
145 public void customKeyGenerator() {
146 CacheResultOperation operation =
147 getCacheOperation(CacheResultOperation.class, CustomService.class, name.getMethodName(), Long.class);
148 assertEquals(defaultCacheResolver, operation.getCacheResolver());
149 assertNull(operation.getExceptionCacheResolver());
150 assertCacheKeyGenerator(operation.getKeyGenerator(), TestableCacheKeyGenerator.class);
151 }
152
153 @Test
154 public void customKeyGeneratorSpringBean() {
155 TestableCacheKeyGenerator bean = new TestableCacheKeyGenerator();
156 beanFactory.registerSingleton("fooBar", bean);
157 CacheResultOperation operation =
158 getCacheOperation(CacheResultOperation.class, CustomService.class, name.getMethodName(), Long.class);
159 assertEquals(defaultCacheResolver, operation.getCacheResolver());
160 assertNull(operation.getExceptionCacheResolver());
161 KeyGeneratorAdapter adapter = (KeyGeneratorAdapter) operation.getKeyGenerator();
162 assertSame(bean, adapter.getTarget());
163 }
164
165 @Test
166 public void customKeyGeneratorAndCacheResolver() {
167 CacheResultOperation operation = getCacheOperation(CacheResultOperation.class,
168 CustomServiceWithDefaults.class, name.getMethodName(), Long.class);
169 assertJCacheResolver(operation.getCacheResolver(), TestableCacheResolver.class);
170 assertJCacheResolver(operation.getExceptionCacheResolver(), null);
171 assertCacheKeyGenerator(operation.getKeyGenerator(), TestableCacheKeyGenerator.class);
172 }
173
174 @Test
175 public void customKeyGeneratorAndCacheResolverWithExceptionName() {
176 CacheResultOperation operation = getCacheOperation(CacheResultOperation.class,
177 CustomServiceWithDefaults.class, name.getMethodName(), Long.class);
178 assertJCacheResolver(operation.getCacheResolver(), TestableCacheResolver.class);
179 assertJCacheResolver(operation.getExceptionCacheResolver(), TestableCacheResolver.class);
180 assertCacheKeyGenerator(operation.getKeyGenerator(), TestableCacheKeyGenerator.class);
181 }
182
183 private void assertDefaults(AbstractJCacheKeyOperation<?> operation) {
184 assertEquals(defaultCacheResolver, operation.getCacheResolver());
185 assertEquals(KeyGeneratorAdapter.class, operation.getKeyGenerator().getClass());
186 assertEquals(defaultKeyGenerator, ((KeyGeneratorAdapter) operation.getKeyGenerator()).getTarget());
187 }
188
189 protected <T extends JCacheOperation<?>> T getDefaultCacheOperation(Class<T> operationType, Class<?>... parameterTypes) {
190 return getCacheOperation(operationType, AnnotatedJCacheableService.class, name.getMethodName(), parameterTypes);
191 }
192
193 protected <T extends JCacheOperation<?>> T getCacheOperation(
194 Class<T> operationType, Class<?> targetType, String methodName, Class<?>... parameterTypes) {
195
196 JCacheOperation<?> result = getCacheOperation(targetType, methodName, parameterTypes);
197 assertNotNull(result);
198 assertEquals(operationType, result.getClass());
199 return operationType.cast(result);
200 }
201
202 private JCacheOperation<?> getCacheOperation(Class<?> targetType, String methodName, Class<?>... parameterTypes) {
203 Method method = ReflectionUtils.findMethod(targetType, methodName, parameterTypes);
204 Assert.notNull(method, "requested method '" + methodName + "'does not exist");
205 return source.getCacheOperation(method, targetType);
206 }
207
208 private void assertJCacheResolver(CacheResolver actual,
209 Class<? extends javax.cache.annotation.CacheResolver> expectedTargetType) {
210
211 if (expectedTargetType == null) {
212 assertNull(actual);
213 }
214 else {
215 assertEquals("Wrong cache resolver implementation", CacheResolverAdapter.class, actual.getClass());
216 CacheResolverAdapter adapter = (CacheResolverAdapter) actual;
217 assertEquals("Wrong target JCache implementation", expectedTargetType, adapter.getTarget().getClass());
218 }
219 }
220
221 private void assertCacheKeyGenerator(KeyGenerator actual,
222 Class<? extends CacheKeyGenerator> expectedTargetType) {
223 assertEquals("Wrong cache resolver implementation", KeyGeneratorAdapter.class, actual.getClass());
224 KeyGeneratorAdapter adapter = (KeyGeneratorAdapter) actual;
225 assertEquals("Wrong target CacheKeyGenerator implementation", expectedTargetType, adapter.getTarget().getClass());
226 }
227
228
229 static class CustomService {
230
231 @CacheResult(cacheKeyGenerator = TestableCacheKeyGenerator.class)
232 public Object customKeyGenerator(Long id) {
233 return null;
234 }
235
236 @CacheResult(cacheKeyGenerator = TestableCacheKeyGenerator.class)
237 public Object customKeyGeneratorSpringBean(Long id) {
238 return null;
239 }
240
241 @CacheResult(cacheResolverFactory = TestableCacheResolverFactory.class)
242 public Object customCacheResolver(Long id) {
243 return null;
244 }
245 }
246
247
248 @CacheDefaults(cacheResolverFactory = TestableCacheResolverFactory.class,
249 cacheKeyGenerator = TestableCacheKeyGenerator.class)
250 static class CustomServiceWithDefaults {
251
252 @CacheResult
253 public Object customKeyGeneratorAndCacheResolver(Long id) {
254 return null;
255 }
256
257 @CacheResult(exceptionCacheName = "exception")
258 public Object customKeyGeneratorAndCacheResolverWithExceptionName(Long id) {
259 return null;
260 }
261 }
262
263
264 static class InvalidCases {
265
266 @CacheRemove
267 @CacheRemoveAll
268 public void multiAnnotations() {
269 }
270 }
271
272 }