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 4865c1a908b..bef1b773c44 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 @@ -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"); * you may not use this file except in compliance with the License. @@ -98,56 +98,59 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria } CacheableOperation parseCacheableAnnotation(AnnotatedElement ae, DefaultCacheConfig defaultConfig, Cacheable cacheable) { - CacheableOperation op = new CacheableOperation(); - - 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()); - - defaultConfig.applyDefault(op); + CacheableOperation.Builder builder = new CacheableOperation.Builder(); + + builder.setCacheNames(cacheable.cacheNames()); + builder.setCondition(cacheable.condition()); + builder.setUnless(cacheable.unless()); + builder.setKey(cacheable.key()); + builder.setKeyGenerator(cacheable.keyGenerator()); + builder.setCacheManager(cacheable.cacheManager()); + builder.setCacheResolver(cacheable.cacheResolver()); + builder.setSync(cacheable.sync()); + builder.setName(ae.toString()); + + defaultConfig.applyDefault(builder); + CacheableOperation op = builder.build(); validateCacheOperation(ae, op); return op; } CacheEvictOperation parseEvictAnnotation(AnnotatedElement ae, DefaultCacheConfig defaultConfig, CacheEvict cacheEvict) { - CacheEvictOperation op = new CacheEvictOperation(); - - 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()); - - defaultConfig.applyDefault(op); + CacheEvictOperation.Builder builder = new CacheEvictOperation.Builder(); + + builder.setCacheNames(cacheEvict.cacheNames()); + builder.setCondition(cacheEvict.condition()); + builder.setKey(cacheEvict.key()); + builder.setKeyGenerator(cacheEvict.keyGenerator()); + builder.setCacheManager(cacheEvict.cacheManager()); + builder.setCacheResolver(cacheEvict.cacheResolver()); + builder.setCacheWide(cacheEvict.allEntries()); + builder.setBeforeInvocation(cacheEvict.beforeInvocation()); + builder.setName(ae.toString()); + + defaultConfig.applyDefault(builder); + CacheEvictOperation op = builder.build(); validateCacheOperation(ae, op); return op; } CacheOperation parsePutAnnotation(AnnotatedElement ae, DefaultCacheConfig defaultConfig, CachePut cachePut) { - CachePutOperation op = new CachePutOperation(); - - 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()); - - defaultConfig.applyDefault(op); + CachePutOperation.Builder builder = new CachePutOperation.Builder(); + + builder.setCacheNames(cachePut.cacheNames()); + builder.setCondition(cachePut.condition()); + builder.setUnless(cachePut.unless()); + builder.setKey(cachePut.key()); + builder.setKeyGenerator(cachePut.keyGenerator()); + builder.setCacheManager(cachePut.cacheManager()); + builder.setCacheResolver(cachePut.cacheResolver()); + builder.setName(ae.toString()); + + defaultConfig.applyDefault(builder); + CachePutOperation op = builder.build(); validateCacheOperation(ae, op); return op; @@ -275,26 +278,26 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria } /** - * Apply the defaults to the specified {@link CacheOperation}. - * @param operation the operation to update + * Apply the defaults to the specified {@link CacheOperation.Builder}. + * @param builder the operation builder to update */ - public void applyDefault(CacheOperation operation) { - if (operation.getCacheNames().isEmpty() && this.cacheNames != null) { - operation.setCacheNames(this.cacheNames); + public void applyDefault(CacheOperation.Builder builder) { + if (builder.getCacheNames().isEmpty() && this.cacheNames != null) { + builder.setCacheNames(this.cacheNames); } - if (!StringUtils.hasText(operation.getKey()) && !StringUtils.hasText(operation.getKeyGenerator()) && + if (!StringUtils.hasText(builder.getKey()) && !StringUtils.hasText(builder.getKeyGenerator()) && StringUtils.hasText(this.keyGenerator)) { - operation.setKeyGenerator(this.keyGenerator); + builder.setKeyGenerator(this.keyGenerator); } - if (StringUtils.hasText(operation.getCacheManager()) || StringUtils.hasText(operation.getCacheResolver())) { + if (StringUtils.hasText(builder.getCacheManager()) || StringUtils.hasText(builder.getCacheResolver())) { // One of these is set so we should not inherit anything } else if (StringUtils.hasText(this.cacheResolver)) { - operation.setCacheResolver(this.cacheResolver); + builder.setCacheResolver(this.cacheResolver); } else if (StringUtils.hasText(this.cacheManager)) { - operation.setCacheManager(this.cacheManager); + builder.setCacheManager(this.cacheManager); } } 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 d66c6dbff5a..3c8210c9947 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,16 +107,17 @@ 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()); - op.setUnless(getAttributeValue(opElement, "unless", "")); - op.setSync(Boolean.valueOf(getAttributeValue(opElement, "sync", "false"))); + CacheableOperation.Builder builder = prop.merge(opElement, + parserContext.getReaderContext(), new CacheableOperation.Builder()); + builder.setUnless(getAttributeValue(opElement, "unless", "")); + builder.setSync(Boolean.valueOf(getAttributeValue(opElement, "sync", "false"))); Collection col = cacheOpMap.get(nameHolder); if (col == null) { col = new ArrayList(2); cacheOpMap.put(nameHolder, col); } - col.add(op); + col.add(builder.build()); } List evictCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHE_EVICT_ELEMENT); @@ -125,16 +126,17 @@ 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 builder = prop.merge(opElement, + parserContext.getReaderContext(), new CacheEvictOperation.Builder()); String wide = opElement.getAttribute("all-entries"); if (StringUtils.hasText(wide)) { - op.setCacheWide(Boolean.valueOf(wide.trim())); + builder.setCacheWide(Boolean.valueOf(wide.trim())); } String after = opElement.getAttribute("before-invocation"); if (StringUtils.hasText(after)) { - op.setBeforeInvocation(Boolean.valueOf(after.trim())); + builder.setBeforeInvocation(Boolean.valueOf(after.trim())); } Collection col = cacheOpMap.get(nameHolder); @@ -142,7 +144,7 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser { col = new ArrayList(2); cacheOpMap.put(nameHolder, col); } - col.add(op); + col.add(builder.build()); } List putCacheMethods = DomUtils.getChildElementsByTagName(definition, CACHE_PUT_ELEMENT); @@ -151,15 +153,16 @@ 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()); - op.setUnless(getAttributeValue(opElement, "unless", "")); + CachePutOperation.Builder builder = prop.merge(opElement, + parserContext.getReaderContext(), new CachePutOperation.Builder()); + builder.setUnless(getAttributeValue(opElement, "unless", "")); Collection col = cacheOpMap.get(nameHolder); if (col == null) { col = new ArrayList(2); cacheOpMap.put(nameHolder, col); } - col.add(op); + col.add(builder.build()); } RootBeanDefinition attributeSourceDefinition = new RootBeanDefinition(NameMatchCacheOperationSource.class); @@ -208,7 +211,7 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser { } } - T merge(Element element, ReaderContext readerCtx, T op) { + T merge(Element element, ReaderContext readerCtx, T builder) { String cache = element.getAttribute("cache"); // sanity check @@ -221,21 +224,21 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser { readerCtx.error("No cache specified specified for " + element.getNodeName(), element); } } - op.setCacheNames(localCaches); + builder.setCacheNames(localCaches); - op.setKey(getAttributeValue(element, "key", this.key)); - op.setKeyGenerator(getAttributeValue(element, "key-generator", this.keyGenerator)); - op.setCacheManager(getAttributeValue(element, "cache-manager", this.cacheManager)); - op.setCondition(getAttributeValue(element, "condition", this.condition)); + builder.setKey(getAttributeValue(element, "key", this.key)); + builder.setKeyGenerator(getAttributeValue(element, "key-generator", this.keyGenerator)); + builder.setCacheManager(getAttributeValue(element, "cache-manager", this.cacheManager)); + builder.setCondition(getAttributeValue(element, "condition", this.condition)); - if (StringUtils.hasText(op.getKey()) && StringUtils.hasText(op.getKeyGenerator())) { + if (StringUtils.hasText(builder.getKey()) && StringUtils.hasText(builder.getKeyGenerator())) { throw new IllegalStateException("Invalid cache advice configuration on '" + element.toString() + "'. Both 'key' and 'keyGenerator' attributes have been set. " + "These attributes are mutually exclusive: either set the SpEL expression used to" + "compute the key at runtime or set the name of the KeyGenerator bean to use."); } - return op; + return builder; } String merge(Element element, ReaderContext readerCtx) { 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 6bb937a5c5b..8c3e11c96f7 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 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. @@ -24,34 +24,50 @@ package org.springframework.cache.interceptor; */ public class CacheEvictOperation extends CacheOperation { - private boolean cacheWide = false; + private final boolean cacheWide; - private boolean beforeInvocation = false; - - - public void setCacheWide(boolean cacheWide) { - this.cacheWide = cacheWide; - } + private final boolean beforeInvocation; public boolean isCacheWide() { return this.cacheWide; } - public void setBeforeInvocation(boolean beforeInvocation) { - this.beforeInvocation = beforeInvocation; - } - public boolean isBeforeInvocation() { return this.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(CacheEvictOperation.Builder b) { + super(b); + this.cacheWide = b.cacheWide; + this.beforeInvocation = b.beforeInvocation; + } + + public static class Builder extends CacheOperation.Builder { + + private boolean cacheWide = false; + + private boolean beforeInvocation = false; + + 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 3ae277a5838..1d10b3b1d58 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,88 +31,62 @@ 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; - public void setName(String name) { - Assert.hasText(name); - this.name = name; + 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 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; @@ -121,6 +95,7 @@ public abstract class CacheOperation implements BasicOperation { /** * This implementation compares the {@code toString()} results. + * * @see #toString() */ @Override @@ -130,6 +105,7 @@ public abstract class CacheOperation implements BasicOperation { /** * This implementation returns {@code toString()}'s hash code. + * * @see #toString() */ @Override @@ -139,29 +115,112 @@ public abstract class CacheOperation implements BasicOperation { /** * 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. + *

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 String toString() { - return getOperationDescription().toString(); + public final String toString() { + return this.toString; } - /** - * 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 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 this.cacheNames; + } + + public void setKey(String key) { + Assert.notNull(key); + this.key = key; + } + + public String getKey() { + return this.key; + } + + public String getKeyGenerator() { + return this.keyGenerator; + } + + public String getCacheManager() { + return this.cacheManager; + } + + public String getCacheResolver() { + return this.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(this.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 58446d45c1d..295cfc75919 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 { + + 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; + } - @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 23e8d9ff11b..4375f322108 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,54 @@ package org.springframework.cache.interceptor; */ public class CacheableOperation extends CacheOperation { - private String unless; + private final String unless; 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); + } } }