Browse Source

Retrofit Sort with TypedPropertyPath.

issue/3400
Mark Paluch 2 months ago
parent
commit
fa1cf89dbc
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 103
      src/main/java/org/springframework/data/domain/Sort.java
  2. 55
      src/test/java/org/springframework/data/domain/SortUnitTests.java

103
src/main/java/org/springframework/data/domain/Sort.java

@ -31,7 +31,9 @@ import org.jspecify.annotations.Nullable; @@ -31,7 +31,9 @@ import org.jspecify.annotations.Nullable;
import org.springframework.data.util.MethodInvocationRecorder;
import org.springframework.data.util.MethodInvocationRecorder.Recorded;
import org.springframework.data.util.PropertyPath;
import org.springframework.data.util.Streamable;
import org.springframework.data.util.TypedPropertyPath;
import org.springframework.lang.CheckReturnValue;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
@ -94,6 +96,24 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord @@ -94,6 +96,24 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
: new Sort(DEFAULT_DIRECTION, Arrays.asList(properties));
}
/**
* Creates a new {@link Sort} for the given properties.
*
* @param properties must not be {@literal null}.
* @return {@link Sort} for the given properties.
* @since 4.1
*/
@SafeVarargs
public static <T> Sort by(TypedPropertyPath<T, ?>... properties) {
Assert.notNull(properties, "Properties must not be null");
return properties.length == 0 //
? Sort.unsorted() //
: new Sort(DEFAULT_DIRECTION, Arrays.stream(properties).map(TypedPropertyPath::of).map(PropertyPath::toDotPath)
.collect(Collectors.toList()));
}
/**
* Creates a new {@link Sort} for the given {@link Order}s.
*
@ -120,6 +140,25 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord @@ -120,6 +140,25 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
return new Sort(Arrays.asList(orders));
}
/**
* Creates a new {@link Sort} for the given {@link Direction} and properties.
*
* @param direction must not be {@literal null}.
* @param properties must not be {@literal null}.
* @return {@link Sort} for the given {@link Direction} and properties.
* @since 4.1
*/
@SafeVarargs
public static <T> Sort by(Direction direction, TypedPropertyPath<T, ?>... properties) {
Assert.notNull(direction, "Direction must not be null");
Assert.notNull(properties, "Properties must not be null");
Assert.isTrue(properties.length > 0, "At least one property must be given");
return by(Arrays.stream(properties).map(TypedPropertyPath::of).map(PropertyPath::toDotPath)
.map(it -> new Order(direction, it)).toList());
}
/**
* Creates a new {@link Sort} for the given {@link Direction} and properties.
*
@ -144,7 +183,9 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord @@ -144,7 +183,9 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
* @param type must not be {@literal null}.
* @return {@link TypedSort} for the given type.
* @since 2.2
* @deprecated since 4.1 in favor of {@link Sort#by(TypedPropertyPath[])}.
*/
@Deprecated(since = "4.1")
public static <T> TypedSort<T> sort(Class<T> type) {
return new TypedSort<>(type);
}
@ -460,6 +501,17 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord @@ -460,6 +501,17 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
this.nullHandling = nullHandling;
}
/**
* Creates a new {@link Order} instance. Takes a property path. Direction defaults to
* {@link Sort#DEFAULT_DIRECTION}.
*
* @param propertyPath must not be {@literal null} or empty.
* @since 4.1
*/
public static <T, P> Order by(TypedPropertyPath<T, P> propertyPath) {
return by(TypedPropertyPath.of(propertyPath).toDotPath());
}
/**
* Creates a new {@link Order} instance. Takes a single property. Direction defaults to
* {@link Sort#DEFAULT_DIRECTION}.
@ -471,6 +523,17 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord @@ -471,6 +523,17 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
return new Order(DEFAULT_DIRECTION, property);
}
/**
* Creates a new {@link Order} instance. Takes a property path. Direction is {@link Direction#ASC} and NullHandling
* {@link NullHandling#NATIVE}.
*
* @param propertyPath must not be {@literal null} or empty.
* @since 4.1
*/
public static <T, P> Order asc(TypedPropertyPath<T, P> propertyPath) {
return asc(TypedPropertyPath.of(propertyPath).toDotPath());
}
/**
* Creates a new {@link Order} instance. Takes a single property. Direction is {@link Direction#ASC} and
* NullHandling {@link NullHandling#NATIVE}.
@ -482,6 +545,17 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord @@ -482,6 +545,17 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
return new Order(Direction.ASC, property, DEFAULT_NULL_HANDLING);
}
/**
* Creates a new {@link Order} instance. Takes a property path. Direction is {@link Direction#DESC} and NullHandling
* {@link NullHandling#NATIVE}.
*
* @param propertyPath must not be {@literal null} or empty.
* @since 4.1
*/
public static <T, P> Order desc(TypedPropertyPath<T, P> propertyPath) {
return desc(TypedPropertyPath.of(propertyPath).toDotPath());
}
/**
* Creates a new {@link Order} instance. Takes a single property. Direction is {@link Direction#DESC} and
* NullHandling {@link NullHandling#NATIVE}.
@ -562,6 +636,19 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord @@ -562,6 +636,19 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
return with(this.direction == Direction.ASC ? Direction.DESC : Direction.ASC);
}
/**
* Returns a new {@link Order} with the {@code propertyPath} applied.
*
* @param propertyPath must not be {@literal null} or empty.
* @return a new {@link Order} with the {@code propertyPath} applied.
* @since 4.1
*/
@Contract("_ -> new")
@CheckReturnValue
public <T, P> Order withProperty(TypedPropertyPath<T, P> propertyPath) {
return withProperty(TypedPropertyPath.of(propertyPath).toDotPath());
}
/**
* Returns a new {@link Order} with the {@code property} name applied.
*
@ -575,6 +662,20 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord @@ -575,6 +662,20 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
return new Order(this.direction, property, this.ignoreCase, this.nullHandling);
}
/**
* Returns a new {@link Sort} instance for the given properties using {@link #getDirection()}.
*
* @param propertyPaths properties to sort by.
* @return a new {@link Sort} instance for the given properties using {@link #getDirection()}.
* @since 4.1
*/
@Contract("_ -> new")
@CheckReturnValue
public <T> Sort withProperties(TypedPropertyPath<T, ?>... propertyPaths) {
return Sort.by(this.direction,
Arrays.stream(propertyPaths).map(TypedPropertyPath::toDotPath).toArray(String[]::new));
}
/**
* Returns a new {@link Sort} instance for the given properties using {@link #getDirection()}.
*
@ -696,7 +797,9 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord @@ -696,7 +797,9 @@ public class Sort implements Streamable<org.springframework.data.domain.Sort.Ord
* @author Oliver Gierke
* @since 2.2
* @soundtrack The Intersphere - Linger (The Grand Delusion)
* @deprecated since 4.1 in favor of {@link Sort#by(org.springframework.data.util.TypedPropertyPath...)}
*/
@Deprecated(since = "4.1")
public static class TypedSort<T> extends Sort {
private static final @Serial long serialVersionUID = -3550403511206745880L;

55
src/test/java/org/springframework/data/domain/SortUnitTests.java

@ -24,6 +24,8 @@ import org.junit.jupiter.api.Test; @@ -24,6 +24,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.geo.Circle;
import org.springframework.data.mapping.Person;
import org.springframework.data.util.TypedPropertyPath;
/**
* Unit test for {@link Sort}.
@ -44,6 +46,29 @@ class SortUnitTests { @@ -44,6 +46,29 @@ class SortUnitTests {
assertThat(Sort.by("foo").iterator().next().getDirection()).isEqualTo(Sort.DEFAULT_DIRECTION);
}
@Test
void appliesDefaultForOrderForProperty() {
assertThat(Sort.by(Person::getFirstName).iterator().next().getDirection()).isEqualTo(Sort.DEFAULT_DIRECTION);
}
@Test
void appliesPropertyPath() {
record PersonHolder(Person person) {
}
assertThat(Sort.by(Person::getFirstName).iterator().next().getProperty()).isEqualTo("firstName");
assertThat(
Sort.by(TypedPropertyPath.of(PersonHolder::person).then(Person::getFirstName)).iterator().next().getProperty())
.isEqualTo("person.firstName");
}
@Test
void appliesPropertyPaths() {
assertThat(Sort.by(Person::getFirstName, Person::getLastName).stream().map(Order::getProperty))
.containsSequence("firstName", "lastName");
}
/**
* Asserts that the class rejects {@code null} as properties array.
*/
@ -74,7 +99,7 @@ class SortUnitTests { @@ -74,7 +99,7 @@ class SortUnitTests {
*/
@Test
void preventsNoProperties() {
assertThatIllegalArgumentException().isThrownBy(() -> Sort.by(Direction.ASC));
assertThatIllegalArgumentException().isThrownBy(() -> Sort.by(Direction.ASC, new String[0]));
}
@Test
@ -108,6 +133,14 @@ class SortUnitTests { @@ -108,6 +133,14 @@ class SortUnitTests {
assertThat(Order.desc("foo").isIgnoreCase()).isFalse();
}
@Test
void orderFactoryMethodsConsiderPropertyPath() {
assertThat(Order.by(Person::getFirstName)).isEqualTo(Order.by("firstName"));
assertThat(Order.asc(Person::getFirstName)).isEqualTo(Order.asc("firstName"));
assertThat(Order.desc(Person::getFirstName)).isEqualTo(Order.desc("firstName"));
}
@Test // DATACMNS-1021
void createsOrderWithDirection() {
@ -166,6 +199,26 @@ class SortUnitTests { @@ -166,6 +199,26 @@ class SortUnitTests {
assertThat(result.isIgnoreCase()).isEqualTo(source.isIgnoreCase());
}
@Test
void createsNewOrderForDifferentPropertyPath() {
var source = Order.desc("foo").nullsFirst().ignoreCase();
var result = source.withProperty(Person::getFirstName);
assertThat(result.getProperty()).isEqualTo("firstName");
assertThat(result.getDirection()).isEqualTo(source.getDirection());
assertThat(result.getNullHandling()).isEqualTo(source.getNullHandling());
assertThat(result.isIgnoreCase()).isEqualTo(source.isIgnoreCase());
}
@Test
void createsNewOrderFromPaths() {
var sort = Order.desc("foo").withProperties(Person::getFirstName, Person::getLastName);
assertThat(sort).isEqualTo(Sort.by(Direction.DESC, "firstName", "lastName"));
}
@Test
@SuppressWarnings("null")
void preventsNullDirection() {

Loading…
Cancel
Save