From 815cc694fd42b6b3ba5cd89f7b392945eca8ec80 Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Wed, 27 Oct 2021 11:07:47 +0200 Subject: [PATCH 1/2] clarify-propertypath - Prepare branch --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 96d5e3af98..de3ad32217 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-commons - 2.6.0-SNAPSHOT + 2.6.0-clarify-propertypath-SNAPSHOT Spring Data Core From 2e0ae186cd1e50b743c5acc71003ba8f2dafc4b1 Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Wed, 27 Oct 2021 11:07:00 +0200 Subject: [PATCH 2/2] Clarify behaviour of PropertyPath, both in tests and documentation. Closes #2491 --- .../data/mapping/PropertyPath.java | 71 +++++++++++++++---- .../data/mapping/PropertyPathUnitTests.java | 12 +++- 2 files changed, 70 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/springframework/data/mapping/PropertyPath.java b/src/main/java/org/springframework/data/mapping/PropertyPath.java index 81f34bff4c..a302fd095a 100644 --- a/src/main/java/org/springframework/data/mapping/PropertyPath.java +++ b/src/main/java/org/springframework/data/mapping/PropertyPath.java @@ -108,7 +108,15 @@ public TypeInformation getOwningType() { } /** - * Returns the name of the {@link PropertyPath}. + * Returns the first part of the {@link PropertyPath}. + * + *
+	 * {@code
+	 * PropertyPath.from("a.b.c", Some.class).getSegment();
+	 * }
+	 * 
+ * + * will result in {@code "a"} * * @return the name will never be {@literal null}. */ @@ -156,7 +164,15 @@ public TypeInformation getTypeInformation() { } /** - * Returns the next nested {@link PropertyPath}. + * Returns the {@link PropertyPath} path that results from removing the first element of the current one. + * + *
+	 * {@code
+	 * System.out.println(PropertyPath.from("a.b.c", Some.class).next().toDotPath());
+	 * }
+	 * 
+ * + * Will result in the output: {@code b.c} * * @return the next nested {@link PropertyPath} or {@literal null} if no nested {@link PropertyPath} available. * @see #hasNext() @@ -214,9 +230,28 @@ public PropertyPath nested(String path) { return PropertyPath.from(lookup, owningType); } - /* - * (non-Javadoc) - * @see java.lang.Iterable#iterator() + /** + * Returns an {@link Iterator} that iterates over all the partial property paths with the same leaf type + * but decreasing length. + * + *
+	 * {@code
+	 * PropertyPath propertyPath = PropertyPath.from("a.b.c", Some.class);
+	 * for (p : propertyPath.iterator()) {
+	 *     System.out.println(p.toDotPath());
+	 * };
+	 * }
+	 * 
+ * + * Results in the output: + * + *
+	 * {@code
+	 * a.b.c
+	 * b.c
+	 * c
+	 * }
+	 * 
*/ public Iterator iterator() { @@ -321,11 +356,18 @@ private PropertyPath requiredNext() { } /** - * Extracts the {@link PropertyPath} chain from the given source {@link String} and type. + * Extracts the {@link PropertyPath} chain from the given source {@link String} and {@link TypeInformation}.
+ * Uses {@link #SPLITTER} by default and {@link #SPLITTER_FOR_QUOTED} for {@link Pattern#quote(String) quoted} + * literals. + *

+ * Separate parts of the path may be separated by {@code "."} or by {@code "_"} or by camel case. When the match to + * properties is ambiguous longer property names are preferred. So for "userAddressCity" the interpretation + * "userAddress.city" is preferred over "user.address.city". + *

* - * @param source - * @param type - * @return + * @param source a String denoting the property path. Must not be {@literal null}. + * @param type the owning type of the property path. Must not be {@literal null}. + * @return a new {@link PropertyPath} guaranteed to be not {@literal null}. */ public static PropertyPath from(String source, Class type) { return from(source, ClassTypeInformation.from(type)); @@ -335,10 +377,15 @@ public static PropertyPath from(String source, Class type) { * Extracts the {@link PropertyPath} chain from the given source {@link String} and {@link TypeInformation}.
* Uses {@link #SPLITTER} by default and {@link #SPLITTER_FOR_QUOTED} for {@link Pattern#quote(String) quoted} * literals. + *

+ * Separate parts of the path may be separated by {@code "."} or by {@code "_"} or by camel case. When the match to + * properties is ambiguous longer property names are preferred. So for "userAddressCity" the interpretation + * "userAddress.city" is preferred over "user.address.city". + *

* - * @param source must not be {@literal null}. - * @param type - * @return + * @param source a String denoting the property path. Must not be {@literal null}. + * @param type the owning type of the property path. Must not be {@literal null}. + * @return a new {@link PropertyPath} guaranteed to be not {@literal null}. */ public static PropertyPath from(String source, TypeInformation type) { diff --git a/src/test/java/org/springframework/data/mapping/PropertyPathUnitTests.java b/src/test/java/org/springframework/data/mapping/PropertyPathUnitTests.java index 128ad222a9..70c67ace53 100755 --- a/src/test/java/org/springframework/data/mapping/PropertyPathUnitTests.java +++ b/src/test/java/org/springframework/data/mapping/PropertyPathUnitTests.java @@ -24,7 +24,6 @@ import java.util.regex.Pattern; import org.junit.jupiter.api.Test; - import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; @@ -34,6 +33,7 @@ * @author Oliver Gierke * @author Christoph Strobl * @author Mark Paluch + * @author Jens Schauder */ @SuppressWarnings("unused") public class PropertyPathUnitTests { @@ -188,6 +188,16 @@ public void returnsCorrectIteratorForMultipleElement() { assertThat(iterator.hasNext()).isFalse(); } + @Test // GH-2491 + public void nextReturnsPathWithoutFirstElement() { + + PropertyPath propertyPath = PropertyPath.from("bar.user.name", Sample.class); + + final PropertyPath next = propertyPath.next(); + assertThat(next).isNotNull(); + assertThat(next.toDotPath()).isEqualTo("user.name"); + } + @Test // DATACMNS-139 public void rejectsInvalidPropertyWithLeadingUnderscore() {