diff --git a/src/main/java/org/springframework/data/keyvalue/aot/KeyValueRuntimeHints.java b/src/main/java/org/springframework/data/keyvalue/aot/KeyValueRuntimeHints.java index 3b0fd1a1..4ba26118 100644 --- a/src/main/java/org/springframework/data/keyvalue/aot/KeyValueRuntimeHints.java +++ b/src/main/java/org/springframework/data/keyvalue/aot/KeyValueRuntimeHints.java @@ -44,7 +44,11 @@ public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) TypeReference.of(KeyValuePartTreeQuery.class)), hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS)); - hints.reflection().registerType(org.springframework.util.comparator.NullSafeComparator.class, + hints.reflection().registerType(TypeReference.of("java.util.Comparators.NaturalOrderComparator"), + builder -> builder.withMethod("compare", + List.of(TypeReference.of(Object.class), TypeReference.of(Object.class)), ExecutableMode.INVOKE)); + + hints.reflection().registerType(TypeReference.of("java.util.Comparators.NullComparator"), builder -> builder.withMethod("compare", List.of(TypeReference.of(Object.class), TypeReference.of(Object.class)), ExecutableMode.INVOKE)); } diff --git a/src/main/java/org/springframework/data/keyvalue/core/PropertyPathComparator.java b/src/main/java/org/springframework/data/keyvalue/core/PropertyPathComparator.java index 9ad51527..244fd98f 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/PropertyPathComparator.java +++ b/src/main/java/org/springframework/data/keyvalue/core/PropertyPathComparator.java @@ -20,30 +20,35 @@ import java.util.Map; import org.springframework.data.mapping.PropertyPath; -import org.springframework.data.util.Lazy; -import org.springframework.util.comparator.NullSafeComparator; +import org.springframework.lang.Nullable; /** + * {@link Comparator} implementation to compare objects based on a {@link PropertyPath}. This comparator obtains the + * value at {@link PropertyPath} from the {@link #compare(Object, Object) given comparison objects} and then performs + * the comparison. + * * @author Christoph Strobl + * @author Mark Paluch * @since 3.1.10 */ public class PropertyPathComparator implements Comparator { + private static final Comparator NULLS_FIRST = Comparator.nullsFirst(Comparator.naturalOrder()); + private static final Comparator NULLS_LAST = Comparator.nullsLast(Comparator.naturalOrder()); + private final String path; private boolean asc = true; private boolean nullsFirst = true; private final Map, PropertyPath> pathCache = new HashMap<>(2); - private Lazy> comparator = Lazy - .of(() -> new NullSafeComparator(Comparator.naturalOrder(), this.nullsFirst)); public PropertyPathComparator(String path) { this.path = path; } @Override - public int compare(T o1, T o2) { + public int compare(@Nullable T o1, @Nullable T o2) { if (o1 == null && o2 == null) { return 0; @@ -56,10 +61,19 @@ public int compare(T o1, T o2) { } PropertyPath propertyPath = pathCache.computeIfAbsent(o1.getClass(), it -> PropertyPath.from(path, it)); - Object value1 = new SimplePropertyPathAccessor<>(o1).getValue(propertyPath); - Object value2 = new SimplePropertyPathAccessor<>(o2).getValue(propertyPath); + Object value1 = getCompareValue(o1, propertyPath); + Object value2 = getCompareValue(o2, propertyPath); + + return getComparator().compare(value1, value2) * (asc ? 1 : -1); + } + + protected Object getCompareValue(T object, PropertyPath propertyPath) { + return new SimplePropertyPathAccessor<>(object).getValue(propertyPath); + } - return comparator.get().compare(value1, value2) * (asc ? 1 : -1); + @SuppressWarnings("unchecked") + private Comparator getComparator() { + return (Comparator) (nullsFirst ? NULLS_FIRST : NULLS_LAST); } /** diff --git a/src/main/java/org/springframework/data/keyvalue/core/SpelPropertyComparator.java b/src/main/java/org/springframework/data/keyvalue/core/SpelPropertyComparator.java index 04a62200..6d41fed9 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/SpelPropertyComparator.java +++ b/src/main/java/org/springframework/data/keyvalue/core/SpelPropertyComparator.java @@ -22,7 +22,6 @@ import org.springframework.expression.spel.support.SimpleEvaluationContext; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import org.springframework.util.comparator.NullSafeComparator; /** * {@link Comparator} implementation using {@link SpelExpression}. @@ -34,6 +33,9 @@ */ public class SpelPropertyComparator implements Comparator { + private static final Comparator NULLS_FIRST = Comparator.nullsFirst(Comparator.naturalOrder()); + private static final Comparator NULLS_LAST = Comparator.nullsLast(Comparator.naturalOrder()); + private final String path; private final SpelExpressionParser parser; @@ -129,7 +131,7 @@ public int compare(T arg1, T arg2) { SpelExpression expressionToUse = getExpression(); SimpleEvaluationContext ctx = SimpleEvaluationContext.forReadOnlyDataBinding().withInstanceMethods().build(); - ctx.setVariable("comparator", new NullSafeComparator(Comparator.naturalOrder(), this.nullsFirst)); + ctx.setVariable("comparator", nullsFirst ? NULLS_FIRST : NULLS_LAST); ctx.setVariable("arg1", arg1); ctx.setVariable("arg2", arg2); diff --git a/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java b/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java index 43314dc6..1be00e94 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/query/PredicateQueryCreator.java @@ -16,6 +16,7 @@ package org.springframework.data.keyvalue.repository.query; import java.util.Collection; +import java.util.Comparator; import java.util.Iterator; import java.util.Map; import java.util.Objects; @@ -35,7 +36,6 @@ import org.springframework.data.repository.query.parser.PartTree; import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; -import org.springframework.util.comparator.NullSafeComparator; /** * {@link AbstractQueryCreator} to create {@link Predicate}-based {@link KeyValueQuery}s. @@ -45,6 +45,8 @@ */ public class PredicateQueryCreator extends AbstractQueryCreator>, Predicate> { + private static final Comparator COMPARATOR = Comparator.nullsFirst(Comparator.naturalOrder()); + public PredicateQueryCreator(PartTree tree, ParameterAccessor parameters) { super(tree, parameters); } @@ -118,6 +120,10 @@ public PredicateBuilder(Part part) { this.part = part; } + static Comparator comparator() { + return (Comparator) COMPARATOR; + } + static PredicateBuilder propertyValueOf(Part part) { return new PredicateBuilder(part); } @@ -152,23 +158,19 @@ public Predicate isNotNull() { } public Predicate isLessThan(Object value) { - return new ValueComparingPredicate(part.getProperty(), - o -> NullSafeComparator.NULLS_HIGH.compare(o, value) == -1 ? true : false); + return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) == -1 ? true : false); } public Predicate isLessThanEqual(Object value) { - return new ValueComparingPredicate(part.getProperty(), - o -> NullSafeComparator.NULLS_HIGH.compare(o, value) <= 0 ? true : false); + return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) <= 0 ? true : false); } public Predicate isGreaterThan(Object value) { - return new ValueComparingPredicate(part.getProperty(), - o -> NullSafeComparator.NULLS_HIGH.compare(o, value) == 1 ? true : false); + return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) == 1 ? true : false); } public Predicate isGreaterThanEqual(Object value) { - return new ValueComparingPredicate(part.getProperty(), - o -> NullSafeComparator.NULLS_HIGH.compare(o, value) >= 0 ? true : false); + return new ValueComparingPredicate(part.getProperty(), o -> comparator().compare(o, value) >= 0 ? true : false); } public Predicate matches(Pattern pattern) { @@ -271,6 +273,7 @@ public Predicate startsWith(Object value) { } public Predicate endsWith(Object value) { + return new ValueComparingPredicate(part.getProperty(), o -> { if (!(o instanceof String s)) { @@ -283,7 +286,6 @@ public Predicate endsWith(Object value) { return s.toLowerCase().endsWith(value.toString().toLowerCase()); }); - } }