From ba4526edb6a5ecad497fb2ad41b7b84c62a0c90f Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Tue, 5 Dec 2023 12:13:14 +0100 Subject: [PATCH] Avoid records as cache keys for performance reasons. Fixes GH-2997. --- .../data/mapping/PropertyPath.java | 39 ++++++++++++- .../callback/EntityCallbackDiscoverer.java | 46 +++++++++++++-- .../PersistentPropertyPathFactory.java | 56 +++++++++++++++---- 3 files changed, 124 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/springframework/data/mapping/PropertyPath.java b/src/main/java/org/springframework/data/mapping/PropertyPath.java index debffac2c..a11dcd212 100644 --- a/src/main/java/org/springframework/data/mapping/PropertyPath.java +++ b/src/main/java/org/springframework/data/mapping/PropertyPath.java @@ -487,5 +487,42 @@ public class PropertyPath implements Streamable { return String.format("%s.%s", owningType.getType().getSimpleName(), toDotPath()); } - private record Key(TypeInformation type, String path) {}; + private static final class Key { + + private final TypeInformation type; + private final String path; + + private Key(TypeInformation type, String path) { + this.type = type; + this.path = path; + } + + @Override + public boolean equals(@Nullable Object obj) { + + if (obj == this) { + return true; + } + + if (!(obj instanceof Key that)) { + return false; + } + + return Objects.equals(this.type, that.type) && + Objects.equals(this.path, that.path); + } + + @Override + public int hashCode() { + return Objects.hash(type, path); + } + + @Override + public String toString() { + + return "Key[" + + "type=" + type + ", " + + "path=" + path + ']'; + } + } } diff --git a/src/main/java/org/springframework/data/mapping/callback/EntityCallbackDiscoverer.java b/src/main/java/org/springframework/data/mapping/callback/EntityCallbackDiscoverer.java index 91175e77a..9e1700d2c 100644 --- a/src/main/java/org/springframework/data/mapping/callback/EntityCallbackDiscoverer.java +++ b/src/main/java/org/springframework/data/mapping/callback/EntityCallbackDiscoverer.java @@ -23,6 +23,7 @@ import java.util.Comparator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; @@ -331,7 +332,7 @@ class EntityCallbackDiscoverer { * * @author Oliver Drotbohm */ - private record EntityCallbackAdapter (EntityCallback delegate, + private record EntityCallbackAdapter(EntityCallback delegate, ResolvableType type) implements EntityCallback { boolean supports(ResolvableType callbackType, ResolvableType entityType) { @@ -342,17 +343,52 @@ class EntityCallbackDiscoverer { /** * Cache key for {@link EntityCallback}, based on event type and source type. */ - private record CallbackCacheKey(ResolvableType callbackType, - @Nullable Class entityType) implements Comparable { + private static final class CallbackCacheKey implements Comparable { private static final Comparator COMPARATOR = Comparators. nullsHigh() // .thenComparing(it -> it.callbackType.toString()) // .thenComparing(it -> it.entityType.getName()); + private final ResolvableType callbackType; + private final Class entityType; + + private CallbackCacheKey(ResolvableType callbackType, Class entityType) { + + this.callbackType = callbackType; + this.entityType = entityType; + } + @Override - public int compareTo(CallbackCacheKey other) { + public int compareTo(@Nullable CallbackCacheKey other) { return COMPARATOR.compare(this, other); } - } + @Override + public boolean equals(@Nullable Object obj) { + + if (obj == this) { + return true; + } + + if (!(obj instanceof CallbackCacheKey that)) { + return false; + } + + return Objects.equals(this.callbackType, that.callbackType) + && Objects.equals(this.entityType, that.entityType); + } + + @Override + public int hashCode() { + return Objects.hash(callbackType, entityType); + } + + @Override + public String toString() { + + return "CallbackCacheKey[" + + "callbackType=" + callbackType + ", " + + "entityType=" + entityType + ']'; + } + } } diff --git a/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPathFactory.java b/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPathFactory.java index d304eca40..322c62dac 100644 --- a/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPathFactory.java +++ b/src/main/java/org/springframework/data/mapping/context/PersistentPropertyPathFactory.java @@ -15,16 +15,7 @@ */ package org.springframework.data.mapping.context; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -279,12 +270,55 @@ class PersistentPropertyPathFactory, P extends return properties; } - record TypeAndPath(TypeInformation type, String path) { + static final class TypeAndPath { + + private final TypeInformation type; + private final String path; + + private TypeAndPath(TypeInformation type, String path) { + this.type = type; + this.path = path; + } public static TypeAndPath of(TypeInformation type, String path) { return new TypeAndPath(type, path); } + public TypeInformation type() { + return type; + } + + public String path() { + return path; + } + + @Override + public boolean equals(@Nullable Object obj) { + + if (obj == this) { + return true; + } + + if (!(obj instanceof TypeAndPath that)) { + return false; + } + + return Objects.equals(this.type, that.type) + && Objects.equals(this.path, that.path); + } + + @Override + public int hashCode() { + return Objects.hash(type, path); + } + + @Override + public String toString() { + + return "TypeAndPath[" + + "type=" + type + ", " + + "path=" + path + ']'; + } } static class DefaultPersistentPropertyPaths>