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 4865c1a908..934d005ab1 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 @@ -98,56 +98,59 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria } CacheableOperation parseCacheableAnnotation(AnnotatedElement ae, DefaultCacheConfig defaultConfig, Cacheable cacheable) { - CacheableOperation op = new CacheableOperation(); + CacheableOperation.Builder opBuilder = new CacheableOperation.Builder(); - op.setCacheNames(cacheable.cacheNames()); - op.setCondition(cacheable.condition()); - op.setUnless(cacheable.unless()); - op.setKey(cacheable.key()); - op.setKeyGenerator(cacheable.keyGenerator()); - op.setCacheManager(cacheable.cacheManager()); - op.setCacheResolver(cacheable.cacheResolver()); - op.setSync(cacheable.sync()); - op.setName(ae.toString()); + opBuilder.setCacheNames(cacheable.cacheNames()); + opBuilder.setCondition(cacheable.condition()); + opBuilder.setUnless(cacheable.unless()); + opBuilder.setKey(cacheable.key()); + opBuilder.setKeyGenerator(cacheable.keyGenerator()); + opBuilder.setCacheManager(cacheable.cacheManager()); + opBuilder.setCacheResolver(cacheable.cacheResolver()); + opBuilder.setSync(cacheable.sync()); + opBuilder.setName(ae.toString()); - defaultConfig.applyDefault(op); + defaultConfig.applyDefault(opBuilder); + CacheableOperation op = opBuilder.build(); validateCacheOperation(ae, op); return op; } CacheEvictOperation parseEvictAnnotation(AnnotatedElement ae, DefaultCacheConfig defaultConfig, CacheEvict cacheEvict) { - CacheEvictOperation op = new CacheEvictOperation(); + CacheEvictOperation.Builder opBuilder = new CacheEvictOperation.Builder(); - op.setCacheNames(cacheEvict.cacheNames()); - op.setCondition(cacheEvict.condition()); - op.setKey(cacheEvict.key()); - op.setKeyGenerator(cacheEvict.keyGenerator()); - op.setCacheManager(cacheEvict.cacheManager()); - op.setCacheResolver(cacheEvict.cacheResolver()); - op.setCacheWide(cacheEvict.allEntries()); - op.setBeforeInvocation(cacheEvict.beforeInvocation()); - op.setName(ae.toString()); + opBuilder.setCacheNames(cacheEvict.cacheNames()); + opBuilder.setCondition(cacheEvict.condition()); + opBuilder.setKey(cacheEvict.key()); + opBuilder.setKeyGenerator(cacheEvict.keyGenerator()); + opBuilder.setCacheManager(cacheEvict.cacheManager()); + opBuilder.setCacheResolver(cacheEvict.cacheResolver()); + opBuilder.setCacheWide(cacheEvict.allEntries()); + opBuilder.setBeforeInvocation(cacheEvict.beforeInvocation()); + opBuilder.setName(ae.toString()); - defaultConfig.applyDefault(op); + defaultConfig.applyDefault(opBuilder); + CacheEvictOperation op = opBuilder.build(); validateCacheOperation(ae, op); return op; } CacheOperation parsePutAnnotation(AnnotatedElement ae, DefaultCacheConfig defaultConfig, CachePut cachePut) { - CachePutOperation op = new CachePutOperation(); + CachePutOperation.Builder opBuilder = new CachePutOperation.Builder(); - op.setCacheNames(cachePut.cacheNames()); - op.setCondition(cachePut.condition()); - op.setUnless(cachePut.unless()); - op.setKey(cachePut.key()); - op.setKeyGenerator(cachePut.keyGenerator()); - op.setCacheManager(cachePut.cacheManager()); - op.setCacheResolver(cachePut.cacheResolver()); - op.setName(ae.toString()); + opBuilder.setCacheNames(cachePut.cacheNames()); + opBuilder.setCondition(cachePut.condition()); + opBuilder.setUnless(cachePut.unless()); + opBuilder.setKey(cachePut.key()); + opBuilder.setKeyGenerator(cachePut.keyGenerator()); + opBuilder.setCacheManager(cachePut.cacheManager()); + opBuilder.setCacheResolver(cachePut.cacheResolver()); + opBuilder.setName(ae.toString()); - defaultConfig.applyDefault(op); + defaultConfig.applyDefault(opBuilder); + CachePutOperation op = opBuilder.build(); validateCacheOperation(ae, op); return op; @@ -278,7 +281,7 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria * Apply the defaults to the specified {@link CacheOperation}. * @param operation the operation to update */ - public void applyDefault(CacheOperation operation) { + public void applyDefault(CacheOperation.Builder operation) { if (operation.getCacheNames().isEmpty() && this.cacheNames != null) { operation.setCacheNames(this.cacheNames); } diff --git a/spring-context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java b/spring-context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java index d66c6dbff5..d07eb37e55 100644 --- a/spring-context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java +++ b/spring-context/src/main/java/org/springframework/cache/config/CacheAdviceParser.java @@ -107,7 +107,7 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser { String name = prop.merge(opElement, parserContext.getReaderContext()); TypedStringValue nameHolder = new TypedStringValue(name); nameHolder.setSource(parserContext.extractSource(opElement)); - CacheableOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheableOperation()); + CacheableOperation.Builder op = prop.merge(opElement, parserContext.getReaderContext(), new CacheableOperation.Builder()); op.setUnless(getAttributeValue(opElement, "unless", "")); op.setSync(Boolean.valueOf(getAttributeValue(opElement, "sync", "false"))); @@ -116,7 +116,7 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser { col = new ArrayList(2); cacheOpMap.put(nameHolder, col); } - col.add(op); + col.add(op.build()); } List evictCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHE_EVICT_ELEMENT); @@ -125,7 +125,7 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser { String name = prop.merge(opElement, parserContext.getReaderContext()); TypedStringValue nameHolder = new TypedStringValue(name); nameHolder.setSource(parserContext.extractSource(opElement)); - CacheEvictOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheEvictOperation()); + CacheEvictOperation.Builder op = prop.merge(opElement, parserContext.getReaderContext(), new CacheEvictOperation.Builder()); String wide = opElement.getAttribute("all-entries"); if (StringUtils.hasText(wide)) { @@ -142,7 +142,7 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser { col = new ArrayList(2); cacheOpMap.put(nameHolder, col); } - col.add(op); + col.add(op.build()); } List putCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHE_PUT_ELEMENT); @@ -151,7 +151,7 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser { String name = prop.merge(opElement, parserContext.getReaderContext()); TypedStringValue nameHolder = new TypedStringValue(name); nameHolder.setSource(parserContext.extractSource(opElement)); - CachePutOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CachePutOperation()); + CachePutOperation.Builder op = prop.merge(opElement, parserContext.getReaderContext(), new CachePutOperation.Builder()); op.setUnless(getAttributeValue(opElement, "unless", "")); Collection col = cacheOpMap.get(nameHolder); @@ -159,7 +159,7 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser { col = new ArrayList(2); cacheOpMap.put(nameHolder, col); } - col.add(op); + col.add(op.build()); } RootBeanDefinition attributeSourceDefinition = new RootBeanDefinition(NameMatchCacheOperationSource.class); @@ -208,7 +208,7 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser { } } - T merge(Element element, ReaderContext readerCtx, T op) { + T merge(Element element, ReaderContext readerCtx, T op) { String cache = element.getAttribute("cache"); // sanity check diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheEvictOperation.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheEvictOperation.java index 6bb937a5c5..e4aaf0503a 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheEvictOperation.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheEvictOperation.java @@ -24,34 +24,49 @@ package org.springframework.cache.interceptor; */ public class CacheEvictOperation extends CacheOperation { - private boolean cacheWide = false; + private final boolean cacheWide; - private boolean beforeInvocation = false; + private final boolean beforeInvocation; + public boolean isCacheWide() { + return this.cacheWide; + } - public void setCacheWide(boolean cacheWide) { - this.cacheWide = cacheWide; - } + public boolean isBeforeInvocation() { + return this.beforeInvocation; + } - public boolean isCacheWide() { - return this.cacheWide; - } + public CacheEvictOperation(CacheEvictOperation.Builder b) { + super(b); + this.cacheWide = b.cacheWide; + this.beforeInvocation = b.beforeInvocation; + } - public void setBeforeInvocation(boolean beforeInvocation) { - this.beforeInvocation = beforeInvocation; - } + public static class Builder extends CacheOperation.Builder { + private boolean cacheWide = false; - public boolean isBeforeInvocation() { - return this.beforeInvocation; - } + private boolean beforeInvocation = false; - @Override - protected StringBuilder getOperationDescription() { - StringBuilder sb = super.getOperationDescription(); - sb.append(","); - sb.append(this.cacheWide); - sb.append(","); - sb.append(this.beforeInvocation); - return sb; - } + public void setCacheWide(boolean cacheWide) { + this.cacheWide = cacheWide; + } + + public void setBeforeInvocation(boolean beforeInvocation) { + this.beforeInvocation = beforeInvocation; + } + + @Override + protected StringBuilder getOperationDescription() { + StringBuilder sb = super.getOperationDescription(); + sb.append(","); + sb.append(this.cacheWide); + sb.append(","); + sb.append(this.beforeInvocation); + return sb; + } + + public CacheEvictOperation build() { + return new CacheEvictOperation(this); + } + } } diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperation.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperation.java index 3ae277a583..ad9300ca04 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperation.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheOperation.java @@ -31,137 +31,197 @@ import org.springframework.util.Assert; */ public abstract class CacheOperation implements BasicOperation { - private String name = ""; + private final String name; - private Set cacheNames = Collections.emptySet(); + private final Set cacheNames; - private String key = ""; + private final String key; - private String keyGenerator = ""; + private final String keyGenerator; - private String cacheManager = ""; + private final String cacheManager; - private String cacheResolver = ""; + private final String cacheResolver; - private String condition = ""; + private final String condition; + + private final String toString; + + protected CacheOperation(Builder b) { + this.name = b.name; + this.cacheNames = b.cacheNames; + this.key = b.key; + this.keyGenerator = b.keyGenerator; + this.cacheManager = b.cacheManager; + this.cacheResolver = b.cacheResolver; + this.condition = b.condition; + this.toString = b.getOperationDescription().toString(); + } + + public String getName() { + return this.name; + } - public void setName(String name) { - Assert.hasText(name); - this.name = name; - } - - public String getName() { - return this.name; - } - - public void setCacheName(String cacheName) { - Assert.hasText(cacheName); - this.cacheNames = Collections.singleton(cacheName); - } - - public void setCacheNames(String... cacheNames) { - this.cacheNames = new LinkedHashSet(cacheNames.length); - for (String cacheName : cacheNames) { - Assert.hasText(cacheName, "Cache name must be non-null if specified"); - this.cacheNames.add(cacheName); - } - } - - @Override - public Set getCacheNames() { - return this.cacheNames; - } - - public void setKey(String key) { - Assert.notNull(key); - this.key = key; - } - - public String getKey() { - return this.key; - } - - public void setKeyGenerator(String keyGenerator) { - Assert.notNull(keyGenerator); - this.keyGenerator = keyGenerator; - } - - public String getKeyGenerator() { - return this.keyGenerator; - } - - public void setCacheManager(String cacheManager) { - Assert.notNull(cacheManager); - this.cacheManager = cacheManager; - } - - public String getCacheManager() { - return this.cacheManager; - } - - public void setCacheResolver(String cacheResolver) { - Assert.notNull(this.cacheManager); - this.cacheResolver = cacheResolver; - } - - public String getCacheResolver() { - return this.cacheResolver; - } - - public void setCondition(String condition) { - Assert.notNull(condition); - this.condition = condition; - } - - public String getCondition() { - return this.condition; - } + @Override + public Set getCacheNames() { + return this.cacheNames; + } - /** - * This implementation compares the {@code toString()} results. - * @see #toString() - */ - @Override - public boolean equals(Object other) { - return (other instanceof CacheOperation && toString().equals(other.toString())); - } + public String getKey() { + return this.key; + } - /** - * This implementation returns {@code toString()}'s hash code. - * @see #toString() - */ - @Override - public int hashCode() { - return toString().hashCode(); - } - /** - * Return an identifying description for this cache operation. - *

Has to be overridden in subclasses for correct {@code equals} - * and {@code hashCode} behavior. Alternatively, {@link #equals} - * and {@link #hashCode} can be overridden themselves. - */ - @Override - public String toString() { - return getOperationDescription().toString(); - } + public String getKeyGenerator() { + return this.keyGenerator; + } - /** - * Return an identifying description for this caching operation. - *

Available to subclasses, for inclusion in their {@code toString()} result. - */ - protected StringBuilder getOperationDescription() { - StringBuilder result = new StringBuilder(getClass().getSimpleName()); - result.append("[").append(this.name); - result.append("] caches=").append(this.cacheNames); - result.append(" | key='").append(this.key); - result.append("' | keyGenerator='").append(this.keyGenerator); - result.append("' | cacheManager='").append(this.cacheManager); - result.append("' | cacheResolver='").append(this.cacheResolver); - result.append("' | condition='").append(this.condition).append("'"); - return result; - } + + public String getCacheManager() { + return this.cacheManager; + } + + + public String getCacheResolver() { + return this.cacheResolver; + } + + + public String getCondition() { + return this.condition; + } + + + /** + * This implementation compares the {@code toString()} results. + * + * @see #toString() + */ + @Override + public boolean equals(Object other) { + return (other instanceof CacheOperation && toString().equals(other.toString())); + } + + /** + * This implementation returns {@code toString()}'s hash code. + * + * @see #toString() + */ + @Override + public int hashCode() { + return toString().hashCode(); + } + + /** + * Return an identifying description for this cache operation. + *

Returned value is produced by calling {@link Builder#getOperationDescription()} + * during object construction. This method is used in {#hashCode} and {#equals}. + * + * @see Builder#getOperationDescription() + */ + @Override + public final String toString() { + return toString; + } + + public abstract static class Builder { + + private String name = ""; + + private Set cacheNames = Collections.emptySet(); + + private String key = ""; + + private String keyGenerator = ""; + + private String cacheManager = ""; + + private String cacheResolver = ""; + + private String condition = ""; + + public void setName(String name) { + Assert.hasText(name); + this.name = name; + } + + public void setCacheName(String cacheName) { + Assert.hasText(cacheName); + this.cacheNames = Collections.singleton(cacheName); + } + + public void setCacheNames(String... cacheNames) { + this.cacheNames = new LinkedHashSet(cacheNames.length); + for (String cacheName : cacheNames) { + Assert.hasText(cacheName, "Cache name must be non-null if specified"); + this.cacheNames.add(cacheName); + } + } + + public Set getCacheNames() { + return cacheNames; + } + + public void setKey(String key) { + Assert.notNull(key); + this.key = key; + } + + public String getKey() { + return key; + } + + public String getKeyGenerator() { + return keyGenerator; + } + + public String getCacheManager() { + return cacheManager; + } + + public String getCacheResolver() { + return cacheResolver; + } + + public void setKeyGenerator(String keyGenerator) { + Assert.notNull(keyGenerator); + this.keyGenerator = keyGenerator; + } + + public void setCacheManager(String cacheManager) { + Assert.notNull(cacheManager); + this.cacheManager = cacheManager; + } + + public void setCacheResolver(String cacheResolver) { + Assert.notNull(cacheManager); + this.cacheResolver = cacheResolver; + } + + public void setCondition(String condition) { + Assert.notNull(condition); + this.condition = condition; + } + + /** + * Return an identifying description for this caching operation. + *

Available to subclasses, for inclusion in their {@code toString()} result. + */ + protected StringBuilder getOperationDescription() { + StringBuilder result = new StringBuilder(getClass().getSimpleName()); + result.append("[").append(this.name); + result.append("] caches=").append(this.cacheNames); + result.append(" | key='").append(this.key); + result.append("' | keyGenerator='").append(this.keyGenerator); + result.append("' | cacheManager='").append(this.cacheManager); + result.append("' | cacheResolver='").append(this.cacheResolver); + result.append("' | condition='").append(this.condition).append("'"); + return result; + } + + public abstract CacheOperation build(); + } } diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CachePutOperation.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CachePutOperation.java index 58446d45c1..e748d2db55 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/CachePutOperation.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CachePutOperation.java @@ -25,23 +25,36 @@ package org.springframework.cache.interceptor; */ public class CachePutOperation extends CacheOperation { - private String unless; + private final String unless; + public CachePutOperation(CachePutOperation.Builder b) { + super(b); + this.unless = b.unless; + } public String getUnless() { return this.unless; } - public void setUnless(String unless) { - this.unless = unless; - } + public static class Builder extends CacheOperation.Builder { - @Override - protected StringBuilder getOperationDescription() { - StringBuilder sb = super.getOperationDescription(); - sb.append(" | unless='"); - sb.append(this.unless); - sb.append("'"); - return sb; - } + private String unless; + + public void setUnless(String unless) { + this.unless = unless; + } + + @Override + protected StringBuilder getOperationDescription() { + StringBuilder sb = super.getOperationDescription(); + sb.append(" | unless='"); + sb.append(this.unless); + sb.append("'"); + return sb; + } + + public CachePutOperation build() { + return new CachePutOperation(this); + } + } } diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheableOperation.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheableOperation.java index 23e8d9ff11..4722d41d2b 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheableOperation.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheableOperation.java @@ -25,36 +25,53 @@ package org.springframework.cache.interceptor; */ public class CacheableOperation extends CacheOperation { - private String unless; + private final String unless; - private boolean sync; + private boolean sync; + public CacheableOperation(CacheableOperation.Builder b) { + super(b); + this.unless = b.unless; + this.sync = b.sync; + } public String getUnless() { return this.unless; } - public void setUnless(String unless) { - this.unless = unless; - } - public boolean isSync() { return this.sync; } - public void setSync(boolean sync) { - this.sync = sync; - } - @Override - protected StringBuilder getOperationDescription() { - StringBuilder sb = super.getOperationDescription(); - sb.append(" | unless='"); - sb.append(this.unless); - sb.append("'"); - sb.append(" | sync='"); - sb.append(this.sync); - sb.append("'"); - return sb; - } + public static class Builder extends CacheOperation.Builder { + + private String unless; + + private boolean sync; + public void setUnless(String unless) { + this.unless = unless; + } + + public void setSync(boolean sync) { + this.sync = sync; + } + + @Override + protected StringBuilder getOperationDescription() { + StringBuilder sb = super.getOperationDescription(); + sb.append(" | unless='"); + sb.append(this.unless); + sb.append("'"); + sb.append(" | sync='"); + sb.append(this.sync); + sb.append("'"); + return sb; + } + + @Override + public CacheableOperation build() { + return new CacheableOperation(this); + } + } }