SpringCacheAnnotationParser properly accepts empty @Caching annotation
Issue: SPR-14162
(cherry picked from commit da11261
)
This commit is contained in:
parent
3829a77894
commit
33dcef3583
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -86,7 +86,10 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
|
||||||
if (cachings != null) {
|
if (cachings != null) {
|
||||||
ops = lazyInit(ops);
|
ops = lazyInit(ops);
|
||||||
for (Caching caching : cachings) {
|
for (Caching caching : cachings) {
|
||||||
ops.addAll(parseCachingAnnotation(ae, cachingConfig, caching));
|
Collection<CacheOperation> cachingOps = parseCachingAnnotation(ae, cachingConfig, caching);
|
||||||
|
if (cachingOps != null) {
|
||||||
|
ops.addAll(cachingOps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -23,10 +23,8 @@ import java.lang.annotation.Target;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
|
@ -37,7 +35,6 @@ import org.springframework.cache.interceptor.CacheableOperation;
|
||||||
import org.springframework.core.annotation.AliasFor;
|
import org.springframework.core.annotation.AliasFor;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,7 +47,7 @@ public class AnnotationCacheOperationSourceTests {
|
||||||
@Rule
|
@Rule
|
||||||
public final ExpectedException exception = ExpectedException.none();
|
public final ExpectedException exception = ExpectedException.none();
|
||||||
|
|
||||||
private AnnotationCacheOperationSource source = new AnnotationCacheOperationSource();
|
private final AnnotationCacheOperationSource source = new AnnotationCacheOperationSource();
|
||||||
|
|
||||||
|
|
||||||
private Collection<CacheOperation> getOps(Class<?> target, String name, int expectedNumberOfOperations) {
|
private Collection<CacheOperation> getOps(Class<?> target, String name, int expectedNumberOfOperations) {
|
||||||
|
@ -86,6 +83,11 @@ public class AnnotationCacheOperationSourceTests {
|
||||||
assertTrue(it.next() instanceof CacheEvictOperation);
|
assertTrue(it.next() instanceof CacheEvictOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emptyCaching() throws Exception {
|
||||||
|
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "emptyCaching", 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void singularStereotype() throws Exception {
|
public void singularStereotype() throws Exception {
|
||||||
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "singleStereotype", 1);
|
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "singleStereotype", 1);
|
||||||
|
@ -105,36 +107,6 @@ public class AnnotationCacheOperationSourceTests {
|
||||||
assertTrue(next.getCacheNames().contains("bar"));
|
assertTrue(next.getCacheNames().contains("bar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO [SPR-13475] Enable test once @Cache* is supported as a composed annotation.
|
|
||||||
@Ignore("Disabled until SPR-13475 is resolved")
|
|
||||||
@Test
|
|
||||||
public void singleComposedAnnotation() throws Exception {
|
|
||||||
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "singleComposed", 1);
|
|
||||||
CacheOperation cacheOperation = ops.iterator().next();
|
|
||||||
assertThat(cacheOperation, instanceOf(CacheableOperation.class));
|
|
||||||
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("composed")));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO [SPR-13475] Enable test once @Cache* is supported as a composed annotation.
|
|
||||||
@Ignore("Disabled until SPR-13475 is resolved")
|
|
||||||
@Test
|
|
||||||
public void multipleComposedAnnotations() throws Exception {
|
|
||||||
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "multipleComposed", 3);
|
|
||||||
Iterator<CacheOperation> it = ops.iterator();
|
|
||||||
|
|
||||||
CacheOperation cacheOperation = it.next();
|
|
||||||
assertThat(cacheOperation, instanceOf(CacheableOperation.class));
|
|
||||||
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("composedCache")));
|
|
||||||
|
|
||||||
cacheOperation = it.next();
|
|
||||||
assertThat(cacheOperation, instanceOf(CacheableOperation.class));
|
|
||||||
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("foo")));
|
|
||||||
|
|
||||||
cacheOperation = it.next();
|
|
||||||
assertThat(cacheOperation, instanceOf(CacheEvictOperation.class));
|
|
||||||
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("composedCache")));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void customKeyGenerator() {
|
public void customKeyGenerator() {
|
||||||
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "customKeyGenerator", 1);
|
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "customKeyGenerator", 1);
|
||||||
|
@ -261,8 +233,10 @@ public class AnnotationCacheOperationSourceTests {
|
||||||
assertSharedConfig(cacheOperation, "classKeyGenerator", "classCacheManager", "", "classCacheName");
|
assertSharedConfig(cacheOperation, "classKeyGenerator", "classCacheManager", "", "classCacheName");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void assertSharedConfig(CacheOperation actual, String keyGenerator, String cacheManager,
|
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 key manager", keyGenerator, actual.getKeyGenerator());
|
||||||
assertEquals("Wrong cache manager", cacheManager, actual.getCacheManager());
|
assertEquals("Wrong cache manager", cacheManager, actual.getCacheManager());
|
||||||
assertEquals("Wrong cache resolver", cacheResolver, actual.getCacheResolver());
|
assertEquals("Wrong cache resolver", cacheResolver, actual.getCacheResolver());
|
||||||
|
@ -272,6 +246,7 @@ public class AnnotationCacheOperationSourceTests {
|
||||||
actual.getCacheNames().contains(cacheName)));
|
actual.getCacheNames().contains(cacheName)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class AnnotatedClass {
|
private static class AnnotatedClass {
|
||||||
|
|
||||||
@Cacheable("test")
|
@Cacheable("test")
|
||||||
|
@ -287,6 +262,10 @@ public class AnnotationCacheOperationSourceTests {
|
||||||
public void caching() {
|
public void caching() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Caching
|
||||||
|
public void emptyCaching() {
|
||||||
|
}
|
||||||
|
|
||||||
@Cacheable(cacheNames = "test", keyGenerator = "custom")
|
@Cacheable(cacheNames = "test", keyGenerator = "custom")
|
||||||
public void customKeyGenerator() {
|
public void customKeyGenerator() {
|
||||||
}
|
}
|
||||||
|
@ -309,13 +288,15 @@ public class AnnotationCacheOperationSourceTests {
|
||||||
public void multipleStereotype() {
|
public void multipleStereotype() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ComposedCacheable("composed")
|
@Cacheable("directly declared")
|
||||||
|
@ComposedCacheable(cacheNames = "composedCache", key = "composedKey")
|
||||||
public void singleComposed() {
|
public void singleComposed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable("directly declared")
|
||||||
@ComposedCacheable(cacheNames = "composedCache", key = "composedKey")
|
@ComposedCacheable(cacheNames = "composedCache", key = "composedKey")
|
||||||
@CacheableFoo
|
@CacheableFoo
|
||||||
@ComposedCacheEvict(cacheNames = "composedCache", key = "composedKey")
|
@ComposedCacheEvict(cacheNames = "composedCacheEvict", key = "composedEvictionKey")
|
||||||
public void multipleComposed() {
|
public void multipleComposed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,6 +329,7 @@ public class AnnotationCacheOperationSourceTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@CacheConfig(cacheNames = "classCacheName",
|
@CacheConfig(cacheNames = "classCacheName",
|
||||||
keyGenerator = "classKeyGenerator",
|
keyGenerator = "classKeyGenerator",
|
||||||
cacheManager = "classCacheManager", cacheResolver = "classCacheResolver")
|
cacheManager = "classCacheManager", cacheResolver = "classCacheResolver")
|
||||||
|
@ -370,6 +352,7 @@ public class AnnotationCacheOperationSourceTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@CacheConfigFoo
|
@CacheConfigFoo
|
||||||
private static class AnnotatedClassWithCustomDefault {
|
private static class AnnotatedClassWithCustomDefault {
|
||||||
|
|
||||||
|
@ -378,6 +361,7 @@ public class AnnotationCacheOperationSourceTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@CacheConfig(cacheNames = "classCacheName",
|
@CacheConfig(cacheNames = "classCacheName",
|
||||||
keyGenerator = "classKeyGenerator",
|
keyGenerator = "classKeyGenerator",
|
||||||
cacheManager = "classCacheManager")
|
cacheManager = "classCacheManager")
|
||||||
|
@ -396,6 +380,7 @@ public class AnnotationCacheOperationSourceTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@CacheConfigFoo
|
@CacheConfigFoo
|
||||||
@CacheConfig(cacheNames = "myCache") // multiple sources
|
@CacheConfig(cacheNames = "myCache") // multiple sources
|
||||||
private static class MultipleCacheConfig {
|
private static class MultipleCacheConfig {
|
||||||
|
@ -405,76 +390,86 @@ public class AnnotationCacheOperationSourceTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
@Cacheable("foo")
|
@Cacheable("foo")
|
||||||
public @interface CacheableFoo {
|
public @interface CacheableFoo {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
@Cacheable(cacheNames = "foo", keyGenerator = "custom")
|
@Cacheable(cacheNames = "foo", keyGenerator = "custom")
|
||||||
public @interface CacheableFooCustomKeyGenerator {
|
public @interface CacheableFooCustomKeyGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
@Cacheable(cacheNames = "foo", cacheManager = "custom")
|
@Cacheable(cacheNames = "foo", cacheManager = "custom")
|
||||||
public @interface CacheableFooCustomCacheManager {
|
public @interface CacheableFooCustomCacheManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
@Cacheable(cacheNames = "foo", cacheResolver = "custom")
|
@Cacheable(cacheNames = "foo", cacheResolver = "custom")
|
||||||
public @interface CacheableFooCustomCacheResolver {
|
public @interface CacheableFooCustomCacheResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
@CacheEvict("foo")
|
@CacheEvict("foo")
|
||||||
public @interface EvictFoo {
|
public @interface EvictFoo {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
@CacheEvict("bar")
|
@CacheEvict("bar")
|
||||||
public @interface EvictBar {
|
public @interface EvictBar {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@CacheConfig(keyGenerator = "classKeyGenerator",
|
@CacheConfig(keyGenerator = "classKeyGenerator",
|
||||||
cacheManager = "classCacheManager", cacheResolver = "classCacheResolver")
|
cacheManager = "classCacheManager",
|
||||||
|
cacheResolver = "classCacheResolver")
|
||||||
public @interface CacheConfigFoo {
|
public @interface CacheConfigFoo {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||||
@Cacheable(cacheNames = "shadowed cache name", key = "shadowed key")
|
@Cacheable(cacheNames = "shadowed cache name", key = "shadowed key")
|
||||||
public @interface ComposedCacheable {
|
@interface ComposedCacheable {
|
||||||
|
|
||||||
@AliasFor(annotation = Cacheable.class, attribute = "cacheNames")
|
@AliasFor(annotation = Cacheable.class)
|
||||||
String[] value() default {};
|
String[] value() default {};
|
||||||
|
|
||||||
@AliasFor(annotation = Cacheable.class, attribute = "cacheNames")
|
@AliasFor(annotation = Cacheable.class)
|
||||||
String[] cacheNames() default {};
|
String[] cacheNames() default {};
|
||||||
|
|
||||||
@AliasFor(annotation = Cacheable.class, attribute = "key")
|
@AliasFor(annotation = Cacheable.class)
|
||||||
String key() default "";
|
String key() default "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||||
@CacheEvict(cacheNames = "shadowed cache name", key = "shadowed key")
|
@CacheEvict(cacheNames = "shadowed cache name", key = "shadowed key")
|
||||||
public @interface ComposedCacheEvict {
|
@interface ComposedCacheEvict {
|
||||||
|
|
||||||
@AliasFor(annotation = Cacheable.class, attribute = "cacheNames")
|
@AliasFor(annotation = CacheEvict.class)
|
||||||
String[] value() default {};
|
String[] value() default {};
|
||||||
|
|
||||||
@AliasFor(annotation = Cacheable.class, attribute = "cacheNames")
|
@AliasFor(annotation = CacheEvict.class)
|
||||||
String[] cacheNames() default {};
|
String[] cacheNames() default {};
|
||||||
|
|
||||||
@AliasFor(annotation = Cacheable.class, attribute = "key")
|
@AliasFor(annotation = CacheEvict.class)
|
||||||
String key() default "";
|
String key() default "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue