diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/SimpleKey.java b/spring-context/src/main/java/org/springframework/cache/interceptor/SimpleKey.java index da97487d4a4d..d57708558989 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/SimpleKey.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/SimpleKey.java @@ -39,7 +39,21 @@ public class SimpleKey implements Serializable { private final Object[] params; - private final int hashCode; + /** + * The basic Object.hashCode functionality is to derive the hash code from + * a runtime-specific object identity. This makes SimpleKey hash codes unsafe + * to serialize and share with other JVM runtimes, since if the SimpleKey has + * any parameters of an object type that uses an identity hash code, a hash + * code received from another runtime will not match the hash code the + * receiving runtime would produce for an equal SimpleKey instance. + * + * For most object types this is not likely to cause a problem because an + * identity-based hash code implies an identity-based equals method, and objects + * like that are unlikely to make good cache keys in the first place. But + * enums are a big exception - they are singletons with special serialization + * rules and are fine cache key parameters, but it is important not to + * share their identity-based hash codes. */ + private transient int hashCode; /** @@ -61,6 +75,10 @@ public boolean equals(@Nullable Object other) { @Override public final int hashCode() { + // If this instance was deserialized instead of constructed its hashCode may not be initialized. + if (this.hashCode == 0) { + this.hashCode = Arrays.deepHashCode(this.params); + } return this.hashCode; }