Avoid records as cache keys for performance reasons.

Fixes GH-2997.
This commit is contained in:
Oliver Drotbohm
2023-12-05 12:13:14 +01:00
parent fa9d7bdce7
commit ba4526edb6
3 changed files with 124 additions and 17 deletions

View File

@@ -487,5 +487,42 @@ public class PropertyPath implements Streamable<PropertyPath> {
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 + ']';
}
}
}

View File

@@ -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<T> (EntityCallback<T> delegate,
private record EntityCallbackAdapter<T>(EntityCallback<T> delegate,
ResolvableType type) implements EntityCallback<T> {
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<CallbackCacheKey> {
private static final class CallbackCacheKey implements Comparable<CallbackCacheKey> {
private static final Comparator<CallbackCacheKey> COMPARATOR = Comparators.<CallbackCacheKey> 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 + ']';
}
}
}

View File

@@ -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<E extends PersistentEntity<?, P>, 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<T, P extends PersistentProperty<P>>