From 54aeb7a5d6f9f330a25c4ce7a097bfed73a547b5 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sat, 26 Mar 2016 14:32:10 +0100 Subject: [PATCH] Cache key classes implement Comparable and consistently provide a toString representation Issue: SPR-14017 --- .../aop/framework/AdvisedSupport.java | 25 ++++++--- .../SpringCacheAnnotationParser.java | 6 +-- .../cache/interceptor/CacheAspectSupport.java | 16 +++++- .../interceptor/CacheEvictOperation.java | 16 ++++-- .../cache/interceptor/CacheOperation.java | 10 ++-- .../cache/interceptor/CachePutOperation.java | 6 +++ .../cache/interceptor/CacheableOperation.java | 2 + .../AbstractApplicationEventMulticaster.java | 21 +++++++- .../expression/AnnotatedElementKey.java | 16 +++++- .../jmx/access/MBeanClientInterceptor.java | 33 ++++++++++-- .../core/annotation/AnnotationUtils.java | 16 +++++- .../support/GenericConversionService.java | 13 ++++- .../support/ReflectivePropertyAccessor.java | 53 +++++++++++-------- .../connection/CachingConnectionFactory.java | 22 ++++++-- ...actFallbackTransactionAttributeSource.java | 21 +++++++- 15 files changed, 222 insertions(+), 54 deletions(-) diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java b/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java index 9b3b307467..40940374d8 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.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. @@ -586,7 +586,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised { * Simple wrapper class around a Method. Used as the key when * caching methods, for efficient equals and hashCode comparisons. */ - private static class MethodCacheKey { + private static final class MethodCacheKey implements Comparable { private final Method method; @@ -599,17 +599,28 @@ public class AdvisedSupport extends ProxyConfig implements Advised { @Override public boolean equals(Object other) { - if (other == this) { - return true; - } - MethodCacheKey otherKey = (MethodCacheKey) other; - return (this.method == otherKey.method); + return (this == other || (other instanceof MethodCacheKey && + this.method == ((MethodCacheKey) other).method)); } @Override public int hashCode() { return this.hashCode; } + + @Override + public String toString() { + return this.method.toString(); + } + + @Override + public int compareTo(MethodCacheKey other) { + int result = this.method.getName().compareTo(other.method.getName()); + if (result == 0) { + result = this.method.toString().compareTo(other.method.toString()); + } + return result; + } } } 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 737cb6f324..72ebab9ae8 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 @@ -101,6 +101,7 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria CacheableOperation parseCacheableAnnotation(AnnotatedElement ae, DefaultCacheConfig defaultConfig, Cacheable cacheable) { CacheableOperation.Builder builder = new CacheableOperation.Builder(); + builder.setName(ae.toString()); builder.setCacheNames(cacheable.cacheNames()); builder.setCondition(cacheable.condition()); builder.setUnless(cacheable.unless()); @@ -109,7 +110,6 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria builder.setCacheManager(cacheable.cacheManager()); builder.setCacheResolver(cacheable.cacheResolver()); builder.setSync(cacheable.sync()); - builder.setName(ae.toString()); defaultConfig.applyDefault(builder); CacheableOperation op = builder.build(); @@ -121,6 +121,7 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria CacheEvictOperation parseEvictAnnotation(AnnotatedElement ae, DefaultCacheConfig defaultConfig, CacheEvict cacheEvict) { CacheEvictOperation.Builder builder = new CacheEvictOperation.Builder(); + builder.setName(ae.toString()); builder.setCacheNames(cacheEvict.cacheNames()); builder.setCondition(cacheEvict.condition()); builder.setKey(cacheEvict.key()); @@ -129,7 +130,6 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria builder.setCacheResolver(cacheEvict.cacheResolver()); builder.setCacheWide(cacheEvict.allEntries()); builder.setBeforeInvocation(cacheEvict.beforeInvocation()); - builder.setName(ae.toString()); defaultConfig.applyDefault(builder); CacheEvictOperation op = builder.build(); @@ -141,6 +141,7 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria CacheOperation parsePutAnnotation(AnnotatedElement ae, DefaultCacheConfig defaultConfig, CachePut cachePut) { CachePutOperation.Builder builder = new CachePutOperation.Builder(); + builder.setName(ae.toString()); builder.setCacheNames(cachePut.cacheNames()); builder.setCondition(cachePut.condition()); builder.setUnless(cachePut.unless()); @@ -148,7 +149,6 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria builder.setKeyGenerator(cachePut.keyGenerator()); builder.setCacheManager(cachePut.cacheManager()); builder.setCacheResolver(cachePut.cacheResolver()); - builder.setName(ae.toString()); defaultConfig.applyDefault(builder); CachePutOperation op = builder.build(); diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java index 591d3f8a7e..db62c91626 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java @@ -746,7 +746,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker } - private static class CacheOperationCacheKey { + private static final class CacheOperationCacheKey implements Comparable { private final CacheOperation cacheOperation; @@ -774,6 +774,20 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker public int hashCode() { return (this.cacheOperation.hashCode() * 31 + this.methodCacheKey.hashCode()); } + + @Override + public String toString() { + return this.cacheOperation + " on " + this.methodCacheKey; + } + + @Override + public int compareTo(CacheOperationCacheKey other) { + int result = this.cacheOperation.getName().compareTo(other.cacheOperation.getName()); + if (result == 0) { + result = this.methodCacheKey.compareTo(other.methodCacheKey); + } + return result; + } } } 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 301f4fd13f..5008154ebc 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 @@ -29,6 +29,13 @@ public class CacheEvictOperation extends CacheOperation { private final boolean beforeInvocation; + + public CacheEvictOperation(CacheEvictOperation.Builder b) { + super(b); + this.cacheWide = b.cacheWide; + this.beforeInvocation = b.beforeInvocation; + } + public boolean isCacheWide() { return this.cacheWide; } @@ -37,12 +44,10 @@ public class CacheEvictOperation extends CacheOperation { return this.beforeInvocation; } - public CacheEvictOperation(CacheEvictOperation.Builder b) { - super(b); - this.cacheWide = b.cacheWide; - this.beforeInvocation = b.beforeInvocation; - } + /** + * @since 4.3 + */ public static class Builder extends CacheOperation.Builder { private boolean cacheWide = false; @@ -71,4 +76,5 @@ public class CacheEvictOperation extends CacheOperation { 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 dd1e230cfb..f545f8503d 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 @@ -48,6 +48,7 @@ public abstract class CacheOperation implements BasicOperation { private final String toString; + protected CacheOperation(Builder b) { this.name = b.name; this.cacheNames = b.cacheNames; @@ -59,11 +60,11 @@ public abstract class CacheOperation implements BasicOperation { this.toString = b.getOperationDescription().toString(); } + public String getName() { return this.name; } - @Override public Set getCacheNames() { return this.cacheNames; @@ -96,7 +97,6 @@ public abstract class CacheOperation implements BasicOperation { /** * This implementation compares the {@code toString()} results. - * * @see #toString() */ @Override @@ -106,7 +106,6 @@ public abstract class CacheOperation implements BasicOperation { /** * This implementation returns {@code toString()}'s hash code. - * * @see #toString() */ @Override @@ -118,7 +117,6 @@ public abstract class CacheOperation implements BasicOperation { * 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 @@ -126,6 +124,10 @@ public abstract class CacheOperation implements BasicOperation { return this.toString; } + + /** + * @since 4.3 + */ public abstract static class Builder { private String name = ""; 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 6ff97f1af5..7ee2b2b74c 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 @@ -28,6 +28,7 @@ public class CachePutOperation extends CacheOperation { private final String unless; + public CachePutOperation(CachePutOperation.Builder b) { super(b); this.unless = b.unless; @@ -37,6 +38,10 @@ public class CachePutOperation extends CacheOperation { return this.unless; } + + /** + * @since 4.3 + */ public static class Builder extends CacheOperation.Builder { private String unless; @@ -58,4 +63,5 @@ public class CachePutOperation extends CacheOperation { 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 fce91274bb..8258412af7 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 @@ -30,6 +30,7 @@ public class CacheableOperation extends CacheOperation { private boolean sync; + public CacheableOperation(CacheableOperation.Builder b) { super(b); this.unless = b.unless; @@ -76,4 +77,5 @@ public class CacheableOperation extends CacheOperation { return new CacheableOperation(this); } } + } diff --git a/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java b/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java index 0eb68e9e5f..b7dd9186a1 100644 --- a/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java +++ b/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.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. @@ -286,7 +286,7 @@ public abstract class AbstractApplicationEventMulticaster /** * Cache key for ListenerRetrievers, based on event type and source type. */ - private static class ListenerCacheKey { + private static final class ListenerCacheKey implements Comparable { private final ResolvableType eventType; @@ -311,6 +311,23 @@ public abstract class AbstractApplicationEventMulticaster public int hashCode() { return (ObjectUtils.nullSafeHashCode(this.eventType) * 29 + ObjectUtils.nullSafeHashCode(this.sourceType)); } + + @Override + public String toString() { + return "ListenerCacheKey [eventType = " + this.eventType + ", sourceType = " + this.sourceType.getName() + "]"; + } + + @Override + public int compareTo(ListenerCacheKey other) { + int result = 0; + if (this.eventType != null) { + result = this.eventType.toString().compareTo(other.eventType.toString()); + } + if (result == 0 && this.sourceType != null) { + result = this.sourceType.getName().compareTo(other.sourceType.getName()); + } + return result; + } } diff --git a/spring-context/src/main/java/org/springframework/context/expression/AnnotatedElementKey.java b/spring-context/src/main/java/org/springframework/context/expression/AnnotatedElementKey.java index 8f7f88a9c2..50812c11c0 100644 --- a/spring-context/src/main/java/org/springframework/context/expression/AnnotatedElementKey.java +++ b/spring-context/src/main/java/org/springframework/context/expression/AnnotatedElementKey.java @@ -30,7 +30,7 @@ import org.springframework.util.ObjectUtils; * @since 4.2 * @see CachedExpressionEvaluator */ -public final class AnnotatedElementKey { +public final class AnnotatedElementKey implements Comparable { private final AnnotatedElement element; @@ -66,4 +66,18 @@ public final class AnnotatedElementKey { return this.element.hashCode() + (this.targetClass != null ? this.targetClass.hashCode() * 29 : 0); } + @Override + public String toString() { + return this.element + (this.targetClass != null ? " on " + this.targetClass : ""); + } + + @Override + public int compareTo(AnnotatedElementKey other) { + int result = this.element.toString().compareTo(other.element.toString()); + if (result == 0 && this.targetClass != null) { + result = this.targetClass.getName().compareTo(other.targetClass.getName()); + } + return result; + } + } diff --git a/spring-context/src/main/java/org/springframework/jmx/access/MBeanClientInterceptor.java b/spring-context/src/main/java/org/springframework/jmx/access/MBeanClientInterceptor.java index fb59a36291..9d7c677731 100644 --- a/spring-context/src/main/java/org/springframework/jmx/access/MBeanClientInterceptor.java +++ b/spring-context/src/main/java/org/springframework/jmx/access/MBeanClientInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 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. @@ -63,6 +63,7 @@ import org.springframework.jmx.support.JmxUtils; import org.springframework.jmx.support.ObjectNameManager; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; /** * {@link org.aopalliance.intercept.MethodInterceptor} that routes calls to an @@ -609,7 +610,7 @@ public class MBeanClientInterceptor * Simple wrapper class around a method name and its signature. * Used as the key when caching methods. */ - private static class MethodCacheKey { + private static final class MethodCacheKey implements Comparable { private final String name; @@ -628,7 +629,7 @@ public class MBeanClientInterceptor @Override public boolean equals(Object other) { - if (other == this) { + if (this == other) { return true; } MethodCacheKey otherKey = (MethodCacheKey) other; @@ -639,6 +640,32 @@ public class MBeanClientInterceptor public int hashCode() { return this.name.hashCode(); } + + @Override + public String toString() { + return this.name + "(" + StringUtils.arrayToCommaDelimitedString(this.parameterTypes) + ")"; + } + + @Override + public int compareTo(MethodCacheKey other) { + int result = this.name.compareTo(other.name); + if (result != 0) { + return result; + } + if (this.parameterTypes.length < other.parameterTypes.length) { + return -1; + } + if (this.parameterTypes.length > other.parameterTypes.length) { + return 1; + } + for (int i = 0; i < this.parameterTypes.length; i++) { + result = this.parameterTypes[i].getName().compareTo(other.parameterTypes[i].getName()); + if (result != 0) { + return result; + } + } + return 0; + } } } diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java index 99b7b1473e..51f6189e24 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java @@ -1802,7 +1802,7 @@ public abstract class AnnotationUtils { /** * Cache key for the AnnotatedElement cache. */ - private static class AnnotationCacheKey { + private static final class AnnotationCacheKey implements Comparable { private final AnnotatedElement element; @@ -1829,6 +1829,20 @@ public abstract class AnnotationUtils { public int hashCode() { return (this.element.hashCode() * 29 + this.annotationType.hashCode()); } + + @Override + public String toString() { + return "@" + this.annotationType + " on " + this.element; + } + + @Override + public int compareTo(AnnotationCacheKey other) { + int result = this.element.toString().compareTo(other.element.toString()); + if (result == 0) { + result = this.annotationType.getName().compareTo(other.annotationType.getName()); + } + return result; + } } diff --git a/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java b/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java index 30293fc01e..e051e6cc49 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java +++ b/spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java @@ -435,7 +435,7 @@ public class GenericConversionService implements ConfigurableConversionService { /** * Key for use with the converter cache. */ - private static final class ConverterCacheKey { + private static final class ConverterCacheKey implements Comparable { private final TypeDescriptor sourceType; @@ -470,6 +470,17 @@ public class GenericConversionService implements ConfigurableConversionService { return ("ConverterCacheKey [sourceType = " + this.sourceType + ", targetType = " + this.targetType + "]"); } + + @Override + public int compareTo(ConverterCacheKey other) { + int result = this.sourceType.getResolvableType().toString().compareTo( + other.sourceType.getResolvableType().toString()); + if (result == 0) { + result = this.targetType.getResolvableType().toString().compareTo( + other.targetType.getResolvableType().toString()); + } + return result; + } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java index 4a3a5cfe82..8cb54e8f0a 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.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. @@ -33,7 +33,6 @@ import org.springframework.asm.MethodVisitor; import org.springframework.core.MethodParameter; import org.springframework.core.convert.Property; import org.springframework.core.convert.TypeDescriptor; -import org.springframework.core.style.ToStringCreator; import org.springframework.expression.AccessException; import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationException; @@ -70,11 +69,14 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { } - private final Map readerCache = new ConcurrentHashMap(64); + private final Map readerCache = + new ConcurrentHashMap(64); - private final Map writerCache = new ConcurrentHashMap(64); + private final Map writerCache = + new ConcurrentHashMap(64); - private final Map typeDescriptorCache = new ConcurrentHashMap(64); + private final Map typeDescriptorCache = + new ConcurrentHashMap(64); private InvokerPair lastReadInvokerPair; @@ -96,7 +98,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { if (type.isArray() && name.equals("length")) { return true; } - CacheKey cacheKey = new CacheKey(type, name, target instanceof Class); + PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class); if (this.readerCache.containsKey(cacheKey)) { return true; } @@ -140,7 +142,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { return new TypedValue(Array.getLength(target)); } - CacheKey cacheKey = new CacheKey(type, name, target instanceof Class); + PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class); InvokerPair invoker = this.readerCache.get(cacheKey); lastReadInvokerPair = invoker; @@ -202,7 +204,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { return false; } Class type = (target instanceof Class ? (Class) target : target.getClass()); - CacheKey cacheKey = new CacheKey(type, name, target instanceof Class); + PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class); if (this.writerCache.containsKey(cacheKey)) { return true; } @@ -244,7 +246,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { throw new AccessException("Type conversion failure", evaluationException); } } - CacheKey cacheKey = new CacheKey(type, name, target instanceof Class); + PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class); Member cachedMember = this.writerCache.get(cacheKey); if (cachedMember == null || cachedMember instanceof Method) { @@ -301,7 +303,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { if (type.isArray() && name.equals("length")) { return TypeDescriptor.valueOf(Integer.TYPE); } - CacheKey cacheKey = new CacheKey(type, name, target instanceof Class); + PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class); TypeDescriptor typeDescriptor = this.typeDescriptorCache.get(cacheKey); if (typeDescriptor == null) { // attempt to populate the cache entry @@ -466,7 +468,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { return this; } - CacheKey cacheKey = new CacheKey(type, name, target instanceof Class); + PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class); InvokerPair invocationTarget = this.readerCache.get(cacheKey); if (invocationTarget == null || invocationTarget.member instanceof Method) { @@ -520,17 +522,17 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { } - private static class CacheKey { + private static final class PropertyCacheKey implements Comparable { private final Class clazz; - private final String name; + private final String property; private boolean targetIsClass; - public CacheKey(Class clazz, String name, boolean targetIsClass) { + public PropertyCacheKey(Class clazz, String name, boolean targetIsClass) { this.clazz = clazz; - this.name = name; + this.property = name; this.targetIsClass = targetIsClass; } @@ -539,23 +541,32 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { if (this == other) { return true; } - if (!(other instanceof CacheKey)) { + if (!(other instanceof PropertyCacheKey)) { return false; } - CacheKey otherKey = (CacheKey) other; - return (this.clazz.equals(otherKey.clazz) && this.name.equals(otherKey.name) && + PropertyCacheKey otherKey = (PropertyCacheKey) other; + return (this.clazz == otherKey.clazz && this.property.equals(otherKey.property) && this.targetIsClass == otherKey.targetIsClass); } @Override public int hashCode() { - return (this.clazz.hashCode() * 29 + this.name.hashCode()); + return (this.clazz.hashCode() * 29 + this.property.hashCode()); } @Override public String toString() { - return new ToStringCreator(this).append("clazz", this.clazz).append("name", - this.name).append("targetIsClass", this.targetIsClass).toString(); + return "CacheKey [clazz=" + this.clazz.getName() + ", property=" + this.property + ", " + + this.property + ", targetIsClass=" + this.targetIsClass + "]"; + } + + @Override + public int compareTo(PropertyCacheKey other) { + int result = this.clazz.getName().compareTo(other.clazz.getName()); + if (result == 0) { + result = this.property.compareTo(other.property); + } + return result; } } diff --git a/spring-jms/src/main/java/org/springframework/jms/connection/CachingConnectionFactory.java b/spring-jms/src/main/java/org/springframework/jms/connection/CachingConnectionFactory.java index f3ec7beef9..14eb99ff3d 100644 --- a/spring-jms/src/main/java/org/springframework/jms/connection/CachingConnectionFactory.java +++ b/spring-jms/src/main/java/org/springframework/jms/connection/CachingConnectionFactory.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. @@ -509,7 +509,7 @@ public class CachingConnectionFactory extends SingleConnectionFactory { * Simple wrapper class around a Destination reference. * Used as the cache key when caching MessageProducer objects. */ - private static class DestinationCacheKey { + private static class DestinationCacheKey implements Comparable { private final Destination destination; @@ -537,7 +537,7 @@ public class CachingConnectionFactory extends SingleConnectionFactory { public boolean equals(Object other) { // Effectively checking object equality as well as toString equality. // On WebSphere MQ, Destination objects do not implement equals... - return (other == this || destinationEquals((DestinationCacheKey) other)); + return (this == other || destinationEquals((DestinationCacheKey) other)); } @Override @@ -547,6 +547,16 @@ public class CachingConnectionFactory extends SingleConnectionFactory { // for equivalent destinations... Thanks a lot, WebSphere MQ! return this.destination.getClass().hashCode(); } + + @Override + public String toString() { + return getDestinationString(); + } + + @Override + public int compareTo(DestinationCacheKey other) { + return getDestinationString().compareTo(other.getDestinationString()); + } } @@ -584,6 +594,12 @@ public class CachingConnectionFactory extends SingleConnectionFactory { ObjectUtils.nullSafeEquals(this.subscription, otherKey.subscription) && this.durable == otherKey.durable); } + + @Override + public String toString() { + return super.toString() + " [selector=" + this.selector + ", noLocal=" + this.noLocal + + ", subscription=" + this.subscription + ", durable=" + this.durable + "]"; + } } } diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java index 04f1bc2f24..f940403a0f 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.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. @@ -203,7 +203,7 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran /** * Default cache key for the TransactionAttribute cache. */ - private static class DefaultCacheKey { + private static final class DefaultCacheKey implements Comparable { private final Method method; @@ -231,6 +231,23 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran public int hashCode() { return this.method.hashCode() + (this.targetClass != null ? this.targetClass.hashCode() * 29 : 0); } + + @Override + public String toString() { + return this.method + (this.targetClass != null ? " on " + this.targetClass : ""); + } + + @Override + public int compareTo(DefaultCacheKey other) { + int result = this.method.getName().compareTo(other.method.getName()); + if (result == 0) { + result = this.method.toString().compareTo(other.method.toString()); + if (result == 0 && this.targetClass != null) { + result = this.targetClass.getName().compareTo(other.targetClass.getName()); + } + } + return result; + } } }