From 34507ec000e05b4ecf3b95d592eb5ef5cac5c611 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Thu, 13 Dec 2018 16:47:21 +0100 Subject: [PATCH] DATACMNS-1450 - Introduced type-safe Sort API. We now expose a TypedSort that can use method handles to define properties to sort by. Sort.sort(Person.class).by(Person::getName).ascending(); Related tickets: DATACMNS-1449. --- .../org/springframework/data/domain/Sort.java | 93 +++++++++++++++++++ .../data/domain/SortUnitTests.java | 28 ++++++ 2 files changed, 121 insertions(+) diff --git a/src/main/java/org/springframework/data/domain/Sort.java b/src/main/java/org/springframework/data/domain/Sort.java index 569ce8e51..94f464a5a 100644 --- a/src/main/java/org/springframework/data/domain/Sort.java +++ b/src/main/java/org/springframework/data/domain/Sort.java @@ -23,8 +23,11 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Optional; +import java.util.function.Function; import java.util.stream.Collectors; +import org.springframework.data.util.MethodInvocationRecorder; +import org.springframework.data.util.MethodInvocationRecorder.Recorded; import org.springframework.data.util.Streamable; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -169,6 +172,17 @@ public class Sort implements Streamable TypedSort sort(Class type) { + return new TypedSort<>(type); + } + /** * Returns a {@link Sort} instances representing no sorting setup at all. * @@ -692,4 +706,83 @@ public class Sort implements Streamable extends Sort { + + private static final long serialVersionUID = -3550403511206745880L; + + private final Recorded recorded; + + private TypedSort(Class type) { + this(MethodInvocationRecorder.forProxyOf(type)); + } + + private TypedSort(Recorded recorded) { + + super(new Order[0]); + this.recorded = recorded; + } + + public TypedSort by(Function property) { + return new TypedSort<>(recorded.record(property)); + } + + public TypedSort by(Recorded.ToCollectionConverter collectionProperty) { + return new TypedSort<>(recorded.record(collectionProperty)); + } + + public TypedSort by(Recorded.ToMapConverter mapProperty) { + return new TypedSort<>(recorded.record(mapProperty)); + } + + public Sort ascending() { + return withDirection(Sort::ascending); + } + + public Sort descending() { + return withDirection(Sort::descending); + } + + private Sort withDirection(Function direction) { + + return recorded.getPropertyPath() // + .map(Sort::by) // + .map(direction) // + .orElseGet(Sort::unsorted); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.domain.Sort#iterator() + */ + @Override + public Iterator iterator() { + + return recorded.getPropertyPath() // + .map(Order::by) // + .map(Collections::singleton) // + .orElseGet(Collections::emptySet).iterator(); + + } + + /* + * (non-Javadoc) + * @see org.springframework.data.domain.Sort#toString() + */ + @Override + public String toString() { + + return recorded.getPropertyPath() // + .map(Sort::by) // + .orElseGet(Sort::unsorted) // + .toString(); + } + } } diff --git a/src/test/java/org/springframework/data/domain/SortUnitTests.java b/src/test/java/org/springframework/data/domain/SortUnitTests.java index 4d934929b..bd243c9d9 100755 --- a/src/test/java/org/springframework/data/domain/SortUnitTests.java +++ b/src/test/java/org/springframework/data/domain/SortUnitTests.java @@ -18,6 +18,10 @@ package org.springframework.data.domain; import static org.assertj.core.api.Assertions.*; import static org.springframework.data.domain.Sort.NullHandling.*; +import lombok.Getter; + +import java.util.Collection; + import org.junit.Test; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Order; @@ -172,4 +176,28 @@ public class SortUnitTests { .isThrownBy(() -> Sort.by((Direction) null, "foo"))// .withMessageContaining("Direction"); } + + @Test // DATACMNS-1450 + public void translatesTypedSortCorrectly() { + + assertThat(Sort.sort(Sample.class).by(Sample::getNested).by(Nested::getFirstname)) // + .containsExactly(Order.by("nested.firstname")); + + assertThat(Sort.sort(Sample.class).by((Sample it) -> it.getNested().getFirstname())) // + .containsExactly(Order.by("nested.firstname")); + + assertThat(Sort.sort(Sample.class).by(Sample::getNesteds).by(Nested::getFirstname)) // + .containsExactly(Order.by("nesteds.firstname")); + } + + @Getter + static class Sample { + Nested nested; + Collection nesteds; + } + + @Getter + static class Nested { + String firstname; + } }