diff --git a/org.springframework.context.support/src/main/resources/org/springframework/cache/config/spring-cache-3.1.xsd b/org.springframework.context.support/src/main/resources/org/springframework/cache/config/spring-cache-3.1.xsd
new file mode 100644
index 00000000000..076fdbc91ce
--- /dev/null
+++ b/org.springframework.context.support/src/main/resources/org/springframework/cache/config/spring-cache-3.1.xsd
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java
index 0851d702656..9aab40515bf 100644
--- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java
+++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/AnnotationCacheOperationSource.java
@@ -34,7 +34,7 @@ import org.springframework.util.Assert;
* Implementation of the {@link org.springframework.cache.interceptor.CacheOperationSource}
* interface for working with caching metadata in JDK 1.5+ annotation format.
*
- *
This class reads Spring's JDK 1.5+ {@link Cacheable}, {@link CacheUpdate} and {@link CacheEvict}
+ *
This class reads Spring's JDK 1.5+ {@link Cacheable}, {@link CachePut} and {@link CacheEvict}
* annotations and exposes corresponding caching operation definition to Spring's cache infrastructure.
* This class may also serve as base class for a custom CacheOperationSource.
*
diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheAnnotationParser.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheAnnotationParser.java
index 44117112c71..d5a54abe9d9 100644
--- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheAnnotationParser.java
+++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheAnnotationParser.java
@@ -26,7 +26,7 @@ import org.springframework.cache.interceptor.CacheOperation;
* Strategy interface for parsing known caching annotation types.
* {@link AnnotationCacheDefinitionSource} delegates to such
* parsers for supporting specific annotation types such as Spring's own
- * {@link Cacheable}, {@link CacheUpdate} or {@link CacheEvict}.
+ * {@link Cacheable}, {@link CachePut} or {@link CacheEvict}.
*
* @author Costin Leau
* @since 3.1
diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheDefinition.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheDefinitions.java
similarity index 80%
rename from org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheDefinition.java
rename to org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheDefinitions.java
index 7151a3470d1..0aa4947f83b 100644
--- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheDefinition.java
+++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheDefinitions.java
@@ -24,7 +24,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- * Group annotation for multiple cacheable annotations (of different or the same type).
+ * Group annotation for multiple cache annotations (of different or the same type).
*
* @author Costin Leau
* @since 3.1
@@ -33,11 +33,11 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
-public @interface CacheDefinition {
+public @interface CacheDefinitions {
- Cacheable[] cacheables();
+ Cacheable[] cacheable() default {};
- CacheUpdate[] updates();
+ CachePut[] put() default {};
- CacheEvict[] evicts();
+ CacheEvict[] evict() default {};
}
diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheUpdate.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CachePut.java
similarity index 85%
rename from org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheUpdate.java
rename to org.springframework.context/src/main/java/org/springframework/cache/annotation/CachePut.java
index fee6fb19c7f..dbeb6aeef6f 100644
--- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CacheUpdate.java
+++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CachePut.java
@@ -23,11 +23,13 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import org.springframework.cache.Cache;
+
/**
*
* Annotation indicating that a method (or all methods on a class) trigger(s)
- * a cache update operation. As opposed to {@link Cacheable} annotation, this annotation
- * does not cause the target method to be skipped in case of a cache hit - rather it
+ * a {@link Cache#put(Object, Object)} operation. As opposed to {@link Cacheable} annotation,
+ * this annotation does not cause the target method to be skipped - rather it
* always causes the method to be invoked and its result to be placed into the cache.
*
* @author Costin Leau
@@ -37,7 +39,7 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
-public @interface CacheUpdate {
+public @interface CachePut {
/**
* Name of the caches in which the update takes place.
diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java
index 0ec6c4b5c49..4cffa9f6b28 100644
--- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java
+++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/SpringCacheAnnotationParser.java
@@ -23,13 +23,13 @@ import java.util.Collection;
import org.springframework.cache.interceptor.CacheEvictOperation;
import org.springframework.cache.interceptor.CacheOperation;
-import org.springframework.cache.interceptor.CacheUpdateOperation;
+import org.springframework.cache.interceptor.CachePutOperation;
import org.springframework.cache.interceptor.CacheableOperation;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ObjectUtils;
/**
- * Strategy implementation for parsing Spring's {@link Cacheable}, {@link CacheEvict} and {@link CacheUpdate} annotations.
+ * Strategy implementation for parsing Spring's {@link Cacheable}, {@link CacheEvict} and {@link CachePut} annotations.
*
* @author Costin Leau
* @author Juergen Hoeller
@@ -51,12 +51,12 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
ops = lazyInit(ops);
ops.add(parseEvictAnnotation(ae, evict));
}
- CacheUpdate update = AnnotationUtils.getAnnotation(ae, CacheUpdate.class);
+ CachePut update = AnnotationUtils.getAnnotation(ae, CachePut.class);
if (update != null) {
ops = lazyInit(ops);
ops.add(parseUpdateAnnotation(ae, update));
}
- CacheDefinition definition = AnnotationUtils.getAnnotation(ae, CacheDefinition.class);
+ CacheDefinitions definition = AnnotationUtils.getAnnotation(ae, CacheDefinitions.class);
if (definition != null) {
ops = lazyInit(ops);
ops.addAll(parseDefinitionAnnotation(ae, definition));
@@ -87,8 +87,8 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
return ceo;
}
- CacheOperation parseUpdateAnnotation(AnnotatedElement ae, CacheUpdate ann) {
- CacheUpdateOperation cuo = new CacheUpdateOperation();
+ CacheOperation parseUpdateAnnotation(AnnotatedElement ae, CachePut ann) {
+ CachePutOperation cuo = new CachePutOperation();
cuo.setCacheNames(ann.value());
cuo.setCondition(ann.condition());
cuo.setKey(ann.key());
@@ -96,27 +96,27 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
return cuo;
}
- Collection parseDefinitionAnnotation(AnnotatedElement ae, CacheDefinition ann) {
+ Collection parseDefinitionAnnotation(AnnotatedElement ae, CacheDefinitions ann) {
Collection ops = null;
- Cacheable[] cacheables = ann.cacheables();
+ Cacheable[] cacheables = ann.cacheable();
if (!ObjectUtils.isEmpty(cacheables)) {
ops = lazyInit(ops);
for (Cacheable cacheable : cacheables) {
ops.add(parseCacheableAnnotation(ae, cacheable));
}
}
- CacheEvict[] evicts = ann.evicts();
+ CacheEvict[] evicts = ann.evict();
if (!ObjectUtils.isEmpty(evicts)) {
ops = lazyInit(ops);
for (CacheEvict evict : evicts) {
ops.add(parseEvictAnnotation(ae, evict));
}
}
- CacheUpdate[] updates = ann.updates();
+ CachePut[] updates = ann.put();
if (!ObjectUtils.isEmpty(updates)) {
ops = lazyInit(ops);
- for (CacheUpdate update : updates) {
+ for (CachePut update : updates) {
ops.add(parseUpdateAnnotation(ae, update));
}
}
diff --git a/org.springframework.context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java b/org.springframework.context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java
index 473442ceb67..5150169cc19 100644
--- a/org.springframework.context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java
+++ b/org.springframework.context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java
@@ -16,6 +16,8 @@
package org.springframework.cache.config;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.config.TypedStringValue;
@@ -30,6 +32,7 @@ import org.springframework.cache.annotation.AnnotationCacheOperationSource;
import org.springframework.cache.interceptor.CacheEvictOperation;
import org.springframework.cache.interceptor.CacheInterceptor;
import org.springframework.cache.interceptor.CacheOperation;
+import org.springframework.cache.interceptor.CachePutOperation;
import org.springframework.cache.interceptor.CacheableOperation;
import org.springframework.cache.interceptor.NameMatchCacheOperationSource;
import org.springframework.util.StringUtils;
@@ -52,13 +55,14 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
*/
private static class Props {
- private String key, condition;
+ private String key, condition, method;
private String[] caches = null;
Props(Element root) {
String defaultCache = root.getAttribute("cache");
key = root.getAttribute("key");
condition = root.getAttribute("condition");
+ method = root.getAttribute(METHOD_ATTRIBUTE);
if (StringUtils.hasText(defaultCache)) {
caches = StringUtils.commaDelimitedListToStringArray(defaultCache.trim());
@@ -95,10 +99,24 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
return op;
}
+
+ String merge(Element element, ReaderContext readerCtx) {
+ String m = element.getAttribute(METHOD_ATTRIBUTE);
+
+ if (StringUtils.hasText(m)) {
+ return m.trim();
+ }
+ if (StringUtils.hasText(method)) {
+ return method;
+ }
+ readerCtx.error("No method specified for " + element.getNodeName(), element);
+ return null;
+ }
}
private static final String CACHEABLE_ELEMENT = "cacheable";
private static final String CACHE_EVICT_ELEMENT = "cache-evict";
+ private static final String CACHE_PUT_ELEMENT = "cache-put";
private static final String METHOD_ATTRIBUTE = "method";
private static final String DEFS_ELEMENT = "definitions";
@@ -139,34 +157,60 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
Props prop = new Props(definition);
// add cacheable first
- ManagedMap cacheOpeMap = new ManagedMap();
- cacheOpeMap.setSource(parserContext.extractSource(definition));
+ ManagedMap> cacheOpMap = new ManagedMap>();
+ cacheOpMap.setSource(parserContext.extractSource(definition));
- List updateCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHEABLE_ELEMENT);
+ List cacheableCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHEABLE_ELEMENT);
- for (Element opElement : updateCacheMethods) {
- String name = opElement.getAttribute(METHOD_ATTRIBUTE);
+ for (Element opElement : cacheableCacheMethods) {
+ String name = prop.merge(opElement, parserContext.getReaderContext());
TypedStringValue nameHolder = new TypedStringValue(name);
nameHolder.setSource(parserContext.extractSource(opElement));
CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheableOperation());
- cacheOpeMap.put(nameHolder, op);
+ Collection col = cacheOpMap.get(nameHolder);
+ if (col == null) {
+ col = new ArrayList(2);
+ cacheOpMap.put(nameHolder, col);
+ }
+ col.add(op);
}
List evictCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHE_EVICT_ELEMENT);
for (Element opElement : evictCacheMethods) {
- String name = opElement.getAttribute(METHOD_ATTRIBUTE);
+ String name = prop.merge(opElement, parserContext.getReaderContext());
TypedStringValue nameHolder = new TypedStringValue(name);
nameHolder.setSource(parserContext.extractSource(opElement));
CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheEvictOperation());
- cacheOpeMap.put(nameHolder, op);
+ Collection col = cacheOpMap.get(nameHolder);
+ if (col == null) {
+ col = new ArrayList(2);
+ cacheOpMap.put(nameHolder, col);
+ }
+ col.add(op);
+ }
+
+ List putCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHE_PUT_ELEMENT);
+
+ for (Element opElement : putCacheMethods) {
+ String name = prop.merge(opElement, parserContext.getReaderContext());
+ TypedStringValue nameHolder = new TypedStringValue(name);
+ nameHolder.setSource(parserContext.extractSource(opElement));
+ CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CachePutOperation());
+
+ Collection col = cacheOpMap.get(nameHolder);
+ if (col == null) {
+ col = new ArrayList(2);
+ cacheOpMap.put(nameHolder, col);
+ }
+ col.add(op);
}
RootBeanDefinition attributeSourceDefinition = new RootBeanDefinition(NameMatchCacheOperationSource.class);
attributeSourceDefinition.setSource(parserContext.extractSource(definition));
- attributeSourceDefinition.getPropertyValues().add("nameMap", cacheOpeMap);
+ attributeSourceDefinition.getPropertyValues().add("nameMap", cacheOpMap);
return attributeSourceDefinition;
}
}
\ No newline at end of file
diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java
index 6c9f88fff1f..921c8528761 100644
--- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java
+++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java
@@ -403,7 +403,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
evicts.add(opContext);
}
- if (cacheOperation instanceof CacheUpdateOperation) {
+ if (cacheOperation instanceof CachePutOperation) {
updates.add(opContext);
}
}
diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheOperationEditor.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheOperationEditor.java
deleted file mode 100644
index 97da30b2ad0..00000000000
--- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheOperationEditor.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2011 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.interceptor;
-
-import java.beans.PropertyEditorSupport;
-
-import org.springframework.util.StringUtils;
-
-/**
- * PropertyEditor for {@link CacheOperation} objects. Accepts a String of form
- * action,cache,key,condition
- *
where only action and cache are required. Available definitions for action are
- * cacheable and evict.
- * When specifying multiple caches, use ; as a separator
- *
- * A typical example would be:
- *
cacheable, orders;books, #p0
- *
- *
The tokens need to be specified in the order above.
- *
- * @author Costin Leau
- *
- * @see org.springframework.transaction.TransactionAttributeEditor
- * @see org.springframework.core.Constants
- */
-public class CacheOperationEditor extends PropertyEditorSupport {
-
- /**
- * Format is action, cache, key, condition.
- * Null or the empty string means that the method is non cacheable.
- * @see java.beans.PropertyEditor#setAsText(java.lang.String)
- */
- @Override
- public void setAsText(String text) throws IllegalArgumentException {
- if (StringUtils.hasLength(text)) {
- // tokenize it with ","
- String[] tokens = StringUtils.commaDelimitedListToStringArray(text);
- if (tokens.length < 2) {
- throw new IllegalArgumentException(
- "too little arguments found, at least the cache action and cache name are required");
- }
-
- CacheOperation op;
-
- if ("cacheable".contains(tokens[0])) {
- op = new CacheableOperation();
- }
-
- else if ("evict".contains(tokens[0])) {
- op = new CacheEvictOperation();
- } else {
- throw new IllegalArgumentException("Invalid cache action specified " + tokens[0]);
- }
-
- op.setCacheNames(StringUtils.delimitedListToStringArray(tokens[1], ";"));
-
- if (tokens.length > 2) {
- op.setKey(tokens[2]);
- }
-
- if (tokens.length > 3) {
- op.setCondition(tokens[3]);
- }
-
- setValue(op);
- } else {
- setValue(null);
- }
- }
-}
\ No newline at end of file
diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheUpdateOperation.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CachePutOperation.java
similarity index 84%
rename from org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheUpdateOperation.java
rename to org.springframework.context/src/main/java/org/springframework/cache/interceptor/CachePutOperation.java
index a2cb6c93ea9..5a54b72b680 100644
--- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CacheUpdateOperation.java
+++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/CachePutOperation.java
@@ -17,11 +17,11 @@
package org.springframework.cache.interceptor;
/**
- * Class describing a cache 'update' operation.
+ * Class describing a cache 'put' operation.
*
* @author Costin Leau
* @since 3.1
*/
-public class CacheUpdateOperation extends CacheOperation {
+public class CachePutOperation extends CacheOperation {
}
diff --git a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/NameMatchCacheOperationSource.java b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/NameMatchCacheOperationSource.java
index aae17502ec6..f56c04fa4a0 100644
--- a/org.springframework.context/src/main/java/org/springframework/cache/interceptor/NameMatchCacheOperationSource.java
+++ b/org.springframework.context/src/main/java/org/springframework/cache/interceptor/NameMatchCacheOperationSource.java
@@ -19,11 +19,8 @@ package org.springframework.cache.interceptor;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Collection;
-import java.util.Collections;
-import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
-import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -54,63 +51,44 @@ public class NameMatchCacheOperationSource implements CacheOperationSource, Seri
* @see CacheOperation
* @see CacheOperationEditor
*/
- public void setNameMap(Map nameMap) {
- for (Map.Entry entry : nameMap.entrySet()) {
+ public void setNameMap(Map> nameMap) {
+ for (Map.Entry> entry : nameMap.entrySet()) {
addCacheMethod(entry.getKey(), entry.getValue());
}
}
- /**
- * Parses the given properties into a name/attribute map.
- * Expects method names as keys and String attributes definitions as values,
- * parsable into CacheOperation instances via CacheOperationEditor.
- * @see #setNameMap
- * @see CacheOperationEditor
- */
- public void setProperties(Properties cacheOperations) {
- CacheOperationEditor tae = new CacheOperationEditor();
- Enumeration propNames = cacheOperations.propertyNames();
- while (propNames.hasMoreElements()) {
- String methodName = (String) propNames.nextElement();
- String value = cacheOperations.getProperty(methodName);
- tae.setAsText(value);
- CacheOperation op = (CacheOperation) tae.getValue();
- addCacheMethod(methodName, op);
- }
- }
-
/**
* Add an attribute for a cacheable method.
* Method names can be exact matches, or of the pattern "xxx*",
* "*xxx" or "*xxx*" for matching multiple methods.
* @param methodName the name of the method
- * @param operation operation associated with the method
+ * @param ops operation associated with the method
*/
- public void addCacheMethod(String methodName, CacheOperation operation) {
+ public void addCacheMethod(String methodName, Collection ops) {
if (logger.isDebugEnabled()) {
- logger.debug("Adding method [" + methodName + "] with cache operation [" + operation + "]");
+ logger.debug("Adding method [" + methodName + "] with cache operations [" + ops + "]");
}
- this.nameMap.put(methodName, Collections.singleton(operation));
+ this.nameMap.put(methodName, ops);
}
public Collection getCacheOperations(Method method, Class> targetClass) {
// look for direct name match
String methodName = method.getName();
- Collection attr = this.nameMap.get(methodName);
+ Collection ops = this.nameMap.get(methodName);
- if (attr == null) {
+ if (ops == null) {
// Look for most specific name match.
String bestNameMatch = null;
for (String mappedName : this.nameMap.keySet()) {
if (isMatch(methodName, mappedName)
&& (bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) {
- attr = this.nameMap.get(mappedName);
+ ops = this.nameMap.get(mappedName);
bestNameMatch = mappedName;
}
}
}
- return attr;
+ return ops;
}
/**
diff --git a/org.springframework.context/src/main/resources/org/springframework/cache/config/spring-cache-3.1.xsd b/org.springframework.context/src/main/resources/org/springframework/cache/config/spring-cache-3.1.xsd
index 2ffee69a392..d633418686a 100644
--- a/org.springframework.context/src/main/resources/org/springframework/cache/config/spring-cache-3.1.xsd
+++ b/org.springframework.context/src/main/resources/org/springframework/cache/config/spring-cache-3.1.xsd
@@ -182,35 +182,29 @@
The SpEL expression used for conditioning the method caching.]]>
-
-
-
-
-
-
-
-
+
+
-
-
-
-
+ example, 'get*', 'handle*', '*Order', 'on*Event', etc.]]>
+
+
+
-
-
+
+
+
-
+
cn = cm.getCacheNames();
+ assertTrue(cn.contains("default"));
+ assertTrue(cn.contains("secondary"));
+ assertTrue(cn.contains("primary"));
}
public void testCacheable(CacheableService service) throws Exception {
@@ -201,6 +206,124 @@ public abstract class AbstractAnnotationTests {
assertEquals(three, Integer.valueOf(cache.get(three).get().toString()));
}
+ public void testMultiCache(CacheableService service) {
+ Object o1 = new Object();
+ Object o2 = new Object();
+
+ Cache primary = cm.getCache("primary");
+ Cache secondary = cm.getCache("secondary");
+
+ assertNull(primary.get(o1));
+ assertNull(secondary.get(o1));
+ Object r1 = service.multiCache(o1);
+ assertSame(r1, primary.get(o1).get());
+ assertSame(r1, secondary.get(o1).get());
+
+ Object r2 = service.multiCache(o1);
+ Object r3 = service.multiCache(o1);
+
+ assertSame(r1, r2);
+ assertSame(r1, r3);
+
+ assertNull(primary.get(o2));
+ assertNull(secondary.get(o2));
+ Object r4 = service.multiCache(o2);
+ assertSame(r4, primary.get(o2).get());
+ assertSame(r4, secondary.get(o2).get());
+ }
+
+ public void testMultiEvict(CacheableService service) {
+ Object o1 = new Object();
+
+ Object r1 = service.multiCache(o1);
+ Object r2 = service.multiCache(o1);
+
+ Cache primary = cm.getCache("primary");
+ Cache secondary = cm.getCache("secondary");
+
+ assertSame(r1, r2);
+ assertSame(r1, primary.get(o1).get());
+ assertSame(r1, secondary.get(o1).get());
+
+ service.multiEvict(o1);
+ assertNull(primary.get(o1));
+ assertNull(secondary.get(o1));
+
+ Object r3 = service.multiCache(o1);
+ Object r4 = service.multiCache(o1);
+ assertNotSame(r1, r3);
+ assertSame(r3, r4);
+
+ assertSame(r3, primary.get(o1).get());
+ assertSame(r4, secondary.get(o1).get());
+ }
+
+ public void testMultiPut(CacheableService service) {
+ Object o = Integer.valueOf(1);
+
+ Cache primary = cm.getCache("primary");
+ Cache secondary = cm.getCache("secondary");
+
+ assertNull(primary.get(o));
+ assertNull(secondary.get(o));
+ Object r1 = service.multiUpdate(o);
+ assertSame(r1, primary.get(o).get());
+ assertSame(r1, secondary.get(o).get());
+
+ o = Integer.valueOf(2);
+ assertNull(primary.get(o));
+ assertNull(secondary.get(o));
+ Object r2 = service.multiUpdate(o);
+ assertSame(r2, primary.get(o).get());
+ assertSame(r2, secondary.get(o).get());
+ }
+
+ public void testMultiCacheAndEvict(CacheableService service) {
+ String methodName = "multiCacheAndEvict";
+
+ Cache primary = cm.getCache("primary");
+ Cache secondary = cm.getCache("secondary");
+ Object key = Integer.valueOf(1);
+
+ secondary.put(key, key);
+
+ assertNull(secondary.get(methodName));
+ assertSame(key, secondary.get(key).get());
+
+ Object r1 = service.multiCacheAndEvict(key);
+ assertSame(r1, service.multiCacheAndEvict(key));
+
+ // assert the method name is used
+ assertSame(r1, primary.get(methodName).get());
+ assertNull(secondary.get(methodName));
+ assertNull(secondary.get(key));
+ }
+
+ public void testMultiConditionalCacheAndEvict(CacheableService service) {
+ Cache primary = cm.getCache("primary");
+ Cache secondary = cm.getCache("secondary");
+ Object key = Integer.valueOf(1);
+
+ secondary.put(key, key);
+
+ assertNull(primary.get(key));
+ assertSame(key, secondary.get(key).get());
+
+ Object r1 = service.multiConditionalCacheAndEvict(key);
+ Object r3 = service.multiConditionalCacheAndEvict(key);
+
+ assertTrue(!r1.equals(r3));
+ assertNull(primary.get(key));
+
+ Object key2 = Integer.valueOf(3);
+ Object r2 = service.multiConditionalCacheAndEvict(key2);
+ assertSame(r2, service.multiConditionalCacheAndEvict(key2));
+
+ // assert the method name is used
+ assertSame(r2, primary.get(key2).get());
+ assertNull(secondary.get(key2));
+ }
+
@Test
public void testCacheable() throws Exception {
testCacheable(cs);
@@ -329,4 +452,54 @@ public abstract class AbstractAnnotationTests {
public void testClassConditionalUpdate() {
testConditionalCacheUpdate(ccs);
}
+
+ @Test
+ public void testMultiCache() {
+ testMultiCache(cs);
+ }
+
+ @Test
+ public void testClassMultiCache() {
+ testMultiCache(ccs);
+ }
+
+ @Test
+ public void testMultiEvict() {
+ testMultiEvict(cs);
+ }
+
+ @Test
+ public void testClassMultiEvict() {
+ testMultiEvict(ccs);
+ }
+
+ @Test
+ public void testMultiPut() {
+ testMultiPut(cs);
+ }
+
+ @Test
+ public void testClassMultiPut() {
+ testMultiPut(ccs);
+ }
+
+ @Test
+ public void testMultiCacheAndEvict() {
+ testMultiCacheAndEvict(cs);
+ }
+
+ @Test
+ public void testClassMultiCacheAndEvict() {
+ testMultiCacheAndEvict(ccs);
+ }
+
+ @Test
+ public void testMultiConditionalCacheAndEvict() {
+ testMultiConditionalCacheAndEvict(cs);
+ }
+
+ @Test
+ public void testClassMultiConditionalCacheAndEvict() {
+ testMultiConditionalCacheAndEvict(ccs);
+ }
}
\ No newline at end of file
diff --git a/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java b/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java
index 503b9a52ec8..58cb3983c0d 100644
--- a/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java
+++ b/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java
@@ -18,8 +18,9 @@ package org.springframework.cache.config;
import java.util.concurrent.atomic.AtomicLong;
+import org.springframework.cache.annotation.CacheDefinitions;
import org.springframework.cache.annotation.CacheEvict;
-import org.springframework.cache.annotation.CacheUpdate;
+import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
/**
@@ -62,12 +63,12 @@ public class AnnotatedClassCacheableService implements CacheableService {
return counter.getAndIncrement();
}
- @CacheUpdate("default")
+ @CachePut("default")
public Object update(Object arg1) {
return counter.getAndIncrement();
}
- @CacheUpdate(value = "default", condition = "#arg.equals(3)")
+ @CachePut(value = "default", condition = "#arg.equals(3)")
public Object conditionalUpdate(Object arg) {
return arg;
}
@@ -88,4 +89,31 @@ public class AnnotatedClassCacheableService implements CacheableService {
public Long throwUnchecked(Object arg1) {
throw new UnsupportedOperationException();
}
-}
+
+ // multi annotations
+
+ @CacheDefinitions(cacheable = { @Cacheable("primary"), @Cacheable("secondary") })
+ public Object multiCache(Object arg1) {
+ return counter.getAndIncrement();
+ }
+
+ @CacheDefinitions(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") })
+ public Object multiEvict(Object arg1) {
+ return counter.getAndIncrement();
+ }
+
+ @CacheDefinitions(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") })
+ public Object multiCacheAndEvict(Object arg1) {
+ return counter.getAndIncrement();
+ }
+
+ @CacheDefinitions(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") })
+ public Object multiConditionalCacheAndEvict(Object arg1) {
+ return counter.getAndIncrement();
+ }
+
+ @CacheDefinitions(put = { @CachePut("primary"), @CachePut("secondary") })
+ public Object multiUpdate(Object arg1) {
+ return arg1;
+ }
+}
\ No newline at end of file
diff --git a/org.springframework.context/src/test/java/org/springframework/cache/config/AbstractCacheAdviceNamespaceTests.java b/org.springframework.context/src/test/java/org/springframework/cache/config/CacheAdviceNamespaceTests.java
similarity index 89%
rename from org.springframework.context/src/test/java/org/springframework/cache/config/AbstractCacheAdviceNamespaceTests.java
rename to org.springframework.context/src/test/java/org/springframework/cache/config/CacheAdviceNamespaceTests.java
index c8a31d79f33..6fa45351d38 100644
--- a/org.springframework.context/src/test/java/org/springframework/cache/config/AbstractCacheAdviceNamespaceTests.java
+++ b/org.springframework.context/src/test/java/org/springframework/cache/config/CacheAdviceNamespaceTests.java
@@ -24,7 +24,7 @@ import org.springframework.cache.interceptor.CacheInterceptor;
/**
* @author Costin Leau
*/
-public abstract class AbstractCacheAdviceNamespaceTests extends AbstractAnnotationTests {
+public class CacheAdviceNamespaceTests extends AbstractAnnotationTests {
@Override
diff --git a/org.springframework.context/src/test/java/org/springframework/cache/config/CacheableService.java b/org.springframework.context/src/test/java/org/springframework/cache/config/CacheableService.java
index e145ea3e613..88e87cada87 100644
--- a/org.springframework.context/src/test/java/org/springframework/cache/config/CacheableService.java
+++ b/org.springframework.context/src/test/java/org/springframework/cache/config/CacheableService.java
@@ -50,4 +50,14 @@ public interface CacheableService {
T throwUnchecked(Object arg1);
+ // multi annotations
+ T multiCache(Object arg1);
+
+ T multiEvict(Object arg1);
+
+ T multiCacheAndEvict(Object arg1);
+
+ T multiConditionalCacheAndEvict(Object arg1);
+
+ T multiUpdate(Object arg1);
}
\ No newline at end of file
diff --git a/org.springframework.context/src/test/java/org/springframework/cache/config/DefaultCacheableService.java b/org.springframework.context/src/test/java/org/springframework/cache/config/DefaultCacheableService.java
index 1d796204b1f..5376c56f3b8 100644
--- a/org.springframework.context/src/test/java/org/springframework/cache/config/DefaultCacheableService.java
+++ b/org.springframework.context/src/test/java/org/springframework/cache/config/DefaultCacheableService.java
@@ -18,8 +18,9 @@ package org.springframework.cache.config;
import java.util.concurrent.atomic.AtomicLong;
+import org.springframework.cache.annotation.CacheDefinitions;
import org.springframework.cache.annotation.CacheEvict;
-import org.springframework.cache.annotation.CacheUpdate;
+import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
/**
@@ -65,12 +66,12 @@ public class DefaultCacheableService implements CacheableService {
return counter.getAndIncrement();
}
- @CacheUpdate("default")
+ @CachePut("default")
public Long update(Object arg1) {
return counter.getAndIncrement();
}
- @CacheUpdate(value = "default", condition = "#arg.equals(3)")
+ @CachePut(value = "default", condition = "#arg.equals(3)")
public Long conditionalUpdate(Object arg) {
return Long.valueOf(arg.toString());
}
@@ -94,4 +95,31 @@ public class DefaultCacheableService implements CacheableService {
public Long throwUnchecked(Object arg1) {
throw new UnsupportedOperationException(arg1.toString());
}
+
+ // multi annotations
+
+ @CacheDefinitions(cacheable = { @Cacheable("primary"), @Cacheable("secondary") })
+ public Long multiCache(Object arg1) {
+ return counter.getAndIncrement();
+ }
+
+ @CacheDefinitions(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") })
+ public Long multiEvict(Object arg1) {
+ return counter.getAndIncrement();
+ }
+
+ @CacheDefinitions(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") })
+ public Long multiCacheAndEvict(Object arg1) {
+ return counter.getAndIncrement();
+ }
+
+ @CacheDefinitions(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") })
+ public Long multiConditionalCacheAndEvict(Object arg1) {
+ return counter.getAndIncrement();
+ }
+
+ @CacheDefinitions(put = { @CachePut("primary"), @CachePut("secondary") })
+ public Long multiUpdate(Object arg1) {
+ return Long.valueOf(arg1.toString());
+ }
}
\ No newline at end of file
diff --git a/org.springframework.context/src/test/resources/org/springframework/cache/config/annotationDrivenCacheConfig.xml b/org.springframework.context/src/test/resources/org/springframework/cache/config/annotationDrivenCacheConfig.xml
index c029a56ce44..f0e83281eec 100644
--- a/org.springframework.context/src/test/resources/org/springframework/cache/config/annotationDrivenCacheConfig.xml
+++ b/org.springframework.context/src/test/resources/org/springframework/cache/config/annotationDrivenCacheConfig.xml
@@ -30,6 +30,8 @@
+
+
diff --git a/org.springframework.context/src/test/resources/org/springframework/cache/config/annotationDrivenCacheNamespace.xml b/org.springframework.context/src/test/resources/org/springframework/cache/config/annotationDrivenCacheNamespace.xml
index 5179346d7f3..30127b43529 100644
--- a/org.springframework.context/src/test/resources/org/springframework/cache/config/annotationDrivenCacheNamespace.xml
+++ b/org.springframework.context/src/test/resources/org/springframework/cache/config/annotationDrivenCacheNamespace.xml
@@ -17,6 +17,8 @@
+
+
diff --git a/org.springframework.context/src/test/resources/org/springframework/cache/config/cache-advice.xml b/org.springframework.context/src/test/resources/org/springframework/cache/config/cache-advice.xml
index cc69de1d09a..6af65ab73d6 100644
--- a/org.springframework.context/src/test/resources/org/springframework/cache/config/cache-advice.xml
+++ b/org.springframework.context/src/test/resources/org/springframework/cache/config/cache-advice.xml
@@ -20,6 +20,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -35,6 +55,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -47,6 +83,8 @@
+
+