diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java b/spring-context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java index 72ebab9ae85..d58bd1337fc 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java @@ -87,7 +87,10 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria if (!cachings.isEmpty()) { ops = lazyInit(ops); for (Caching caching : cachings) { - ops.addAll(parseCachingAnnotation(ae, cachingConfig, caching)); + Collection cachingOps = parseCachingAnnotation(ae, cachingConfig, caching); + if (cachingOps != null) { + ops.addAll(cachingOps); + } } } diff --git a/spring-context/src/test/java/org/springframework/cache/annotation/AnnotationCacheOperationSourceTests.java b/spring-context/src/test/java/org/springframework/cache/annotation/AnnotationCacheOperationSourceTests.java index 4b1d1016bff..0de198fbafc 100644 --- a/spring-context/src/test/java/org/springframework/cache/annotation/AnnotationCacheOperationSourceTests.java +++ b/spring-context/src/test/java/org/springframework/cache/annotation/AnnotationCacheOperationSourceTests.java @@ -49,7 +49,7 @@ public class AnnotationCacheOperationSourceTests { @Rule public final ExpectedException exception = ExpectedException.none(); - private AnnotationCacheOperationSource source = new AnnotationCacheOperationSource(); + private final AnnotationCacheOperationSource source = new AnnotationCacheOperationSource(); private Collection getOps(Class target, String name, int expectedNumberOfOperations) { @@ -85,6 +85,11 @@ public class AnnotationCacheOperationSourceTests { assertTrue(it.next() instanceof CacheEvictOperation); } + @Test + public void emptyCaching() throws Exception { + Collection ops = getOps(AnnotatedClass.class, "emptyCaching", 0); + } + @Test public void singularStereotype() throws Exception { Collection ops = getOps(AnnotatedClass.class, "singleStereotype", 1); @@ -272,17 +277,20 @@ public class AnnotationCacheOperationSourceTests { assertSharedConfig(cacheOperation, "classKeyGenerator", "classCacheManager", "", "classCacheName"); } + private void assertSharedConfig(CacheOperation actual, String keyGenerator, String cacheManager, - String cacheResolver, String... cacheNames) { + String cacheResolver, String... cacheNames) { + assertEquals("Wrong key manager", keyGenerator, actual.getKeyGenerator()); assertEquals("Wrong cache manager", cacheManager, actual.getCacheManager()); assertEquals("Wrong cache resolver", cacheResolver, actual.getCacheResolver()); assertEquals("Wrong number of cache names", cacheNames.length, actual.getCacheNames().size()); Arrays.stream(cacheNames).forEach( - cacheName -> assertTrue("Cache '" + cacheName + "' not found in " + actual.getCacheNames(), - actual.getCacheNames().contains(cacheName))); + cacheName -> assertTrue("Cache '" + cacheName + "' not found in " + actual.getCacheNames(), + actual.getCacheNames().contains(cacheName))); } + private static class AnnotatedClass { @Cacheable("test") @@ -298,6 +306,10 @@ public class AnnotationCacheOperationSourceTests { public void caching() { } + @Caching + public void emptyCaching() { + } + @Cacheable(cacheNames = "test", keyGenerator = "custom") public void customKeyGenerator() { } @@ -361,6 +373,7 @@ public class AnnotationCacheOperationSourceTests { } } + @CacheConfig(cacheNames = "classCacheName", keyGenerator = "classKeyGenerator", cacheManager = "classCacheManager", cacheResolver = "classCacheResolver") @@ -383,6 +396,7 @@ public class AnnotationCacheOperationSourceTests { } } + @CacheConfigFoo private static class AnnotatedClassWithCustomDefault { @@ -391,6 +405,7 @@ public class AnnotationCacheOperationSourceTests { } } + @CacheConfig(cacheNames = "classCacheName", keyGenerator = "classKeyGenerator", cacheManager = "classCacheManager") @@ -409,6 +424,7 @@ public class AnnotationCacheOperationSourceTests { } } + @CacheConfigFoo @CacheConfig(cacheNames = "myCache") // multiple sources private static class MultipleCacheConfig { @@ -418,48 +434,58 @@ public class AnnotationCacheOperationSourceTests { } } + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Cacheable("foo") public @interface CacheableFoo { } + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Cacheable(cacheNames = "foo", keyGenerator = "custom") public @interface CacheableFooCustomKeyGenerator { } + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Cacheable(cacheNames = "foo", cacheManager = "custom") public @interface CacheableFooCustomCacheManager { } + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Cacheable(cacheNames = "foo", cacheResolver = "custom") public @interface CacheableFooCustomCacheResolver { } + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @CacheEvict("foo") public @interface EvictFoo { } + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @CacheEvict("bar") public @interface EvictBar { } + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) - @CacheConfig(keyGenerator = "classKeyGenerator", cacheManager = "classCacheManager", cacheResolver = "classCacheResolver") + @CacheConfig(keyGenerator = "classKeyGenerator", + cacheManager = "classCacheManager", + cacheResolver = "classCacheResolver") public @interface CacheConfigFoo { } + @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD, ElementType.TYPE }) @Cacheable(cacheNames = "shadowed cache name", key = "shadowed key") @@ -475,6 +501,7 @@ public class AnnotationCacheOperationSourceTests { String key() default ""; } + @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD, ElementType.TYPE }) @CacheEvict(cacheNames = "shadowed cache name", key = "shadowed key") @@ -490,4 +517,4 @@ public class AnnotationCacheOperationSourceTests { String key() default ""; } -} \ No newline at end of file +}