From 786c2e537df8505aa69d82f7c76946f8f118ae58 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 8 Nov 2023 10:52:59 +0100 Subject: [PATCH] Add property path tests & update reference documentation. See: #1851 Original Pull Request: #2940 --- .../repositories/query-methods-details.adoc | 29 ++++++++++++++++++- .../data/mapping/PropertyPathUnitTests.java | 23 +++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/main/antora/modules/ROOT/pages/repositories/query-methods-details.adoc b/src/main/antora/modules/ROOT/pages/repositories/query-methods-details.adoc index e417be1bc..ea2fddb1b 100644 --- a/src/main/antora/modules/ROOT/pages/repositories/query-methods-details.adoc +++ b/src/main/antora/modules/ROOT/pages/repositories/query-methods-details.adoc @@ -119,7 +119,34 @@ So our method name would be as follows: List findByAddress_ZipCode(ZipCode zipCode); ---- -Because we treat the underscore character as a reserved character, we strongly advise following standard Java naming conventions (that is, not using underscores in property names but using camel case instead). +[NOTE] +==== +Because we treat underscores (`_`) as a reserved character, we strongly advise to follow standard Java naming conventions (that is, not using underscores in property names but applying camel case instead). +==== + +[CAUTION] +==== +.Field Names starting with underscore: +Field names may start with underscores like `String \_name`. +Make sure to preserve the `_` as in `\_name` and use double `_` to split nested paths like `user__name`. + +.Upper Case Field Names: +Field names that are all uppercase can be used as such. +Nested paths if applicable require splitting via `_` as in `USER_name`. + +.Field Names with 2nd uppercase letter: +Field names that consist of a starting lower case letter followed by an uppercase one like `String qCode` can be resolved by starting with two upper case letters as in `QCode`. +Please be aware of potential path ambiguities. + +.Path Ambiguities: +In the following sample the arrangement of properties `qCode` and `q`, with `q` containing a property called `code`, creates an ambiguity for the path `QCode`. +```java +record Container(String qCode, Code q) {} +record Code(String code) {} +``` +Since a direct match on a property is considered first, any potential nested paths will not be considered and the algorithm picks the `qCode` field. +In order to select the `code` field in `q` the underscore notation `Q_Code` is required. +==== [[repositories.collections-and-iterables]] == Repository Methods Returning Collections or Iterables diff --git a/src/test/java/org/springframework/data/mapping/PropertyPathUnitTests.java b/src/test/java/org/springframework/data/mapping/PropertyPathUnitTests.java index 51996eb36..1729a17a0 100755 --- a/src/test/java/org/springframework/data/mapping/PropertyPathUnitTests.java +++ b/src/test/java/org/springframework/data/mapping/PropertyPathUnitTests.java @@ -309,6 +309,19 @@ class PropertyPathUnitTests { assertThat(PropertyPath.from("QCode", Foo.class).toDotPath()).isEqualTo("qCode"); assertThat(PropertyPath.from("zIndex", MyRecord.class).toDotPath()).isEqualTo("zIndex"); assertThat(PropertyPath.from("ZIndex", MyRecord.class).toDotPath()).isEqualTo("zIndex"); + assertThat(PropertyPath.from("_foo.QCode", Sample2.class).toDotPath()).isEqualTo("_foo.qCode"); + assertThat(PropertyPath.from("_fooQCode", Sample2.class).toDotPath()).isEqualTo("_foo.qCode"); + } + + @Test // GH-1851 + void favoursPropertyHitOverNestedPath() { + + assertThat(PropertyPath.from("qCode", NameAmbiguities.class).toDotPath()).isEqualTo("qCode"); + assertThat(PropertyPath.from("QCode", NameAmbiguities.class).toDotPath()).isEqualTo("qCode"); + assertThat(PropertyPath.from("Q_Code", NameAmbiguities.class).toDotPath()).isEqualTo("q.code"); + assertThat(PropertyPath.from("q.code", NameAmbiguities.class).toDotPath()).isEqualTo("q.code"); + assertThat(PropertyPath.from("Q.Code", NameAmbiguities.class).toDotPath()).isEqualTo("q.code"); + assertThat(PropertyPath.from("q_code", NameAmbiguities.class).toDotPath()).isEqualTo("q.code"); } @Test // DATACMNS-257 @@ -458,6 +471,16 @@ class PropertyPathUnitTests { } } + private static class NameAmbiguities { + + String qCode; + Code q; + } + + private static class Code { + String code; + } + private class Bar { private FooBar user;