diff --git a/pom.xml b/pom.xml
index 4ecb4c4709..8e5fdb7494 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-relational-parent
- 3.5.0-SNAPSHOT
+ 3.5.0-qbe-collections-SNAPSHOT
pom
Spring Data Relational Parent
diff --git a/spring-data-jdbc-distribution/pom.xml b/spring-data-jdbc-distribution/pom.xml
index 9c02f50608..1b943feef3 100644
--- a/spring-data-jdbc-distribution/pom.xml
+++ b/spring-data-jdbc-distribution/pom.xml
@@ -14,7 +14,7 @@
org.springframework.data
spring-data-relational-parent
- 3.5.0-SNAPSHOT
+ 3.5.0-qbe-collections-SNAPSHOT
../pom.xml
diff --git a/spring-data-jdbc/pom.xml b/spring-data-jdbc/pom.xml
index aba16d9e30..e19111e36b 100644
--- a/spring-data-jdbc/pom.xml
+++ b/spring-data-jdbc/pom.xml
@@ -6,7 +6,7 @@
4.0.0
spring-data-jdbc
- 3.5.0-SNAPSHOT
+ 3.5.0-qbe-collections-SNAPSHOT
Spring Data JDBC
Spring Data module for JDBC repositories.
@@ -15,7 +15,7 @@
org.springframework.data
spring-data-relational-parent
- 3.5.0-SNAPSHOT
+ 3.5.0-qbe-collections-SNAPSHOT
diff --git a/spring-data-r2dbc/pom.xml b/spring-data-r2dbc/pom.xml
index fd450fd21b..9933a19529 100644
--- a/spring-data-r2dbc/pom.xml
+++ b/spring-data-r2dbc/pom.xml
@@ -6,7 +6,7 @@
4.0.0
spring-data-r2dbc
- 3.5.0-SNAPSHOT
+ 3.5.0-qbe-collections-SNAPSHOT
Spring Data R2DBC
Spring Data module for R2DBC
@@ -15,7 +15,7 @@
org.springframework.data
spring-data-relational-parent
- 3.5.0-SNAPSHOT
+ 3.5.0-qbe-collections-SNAPSHOT
diff --git a/spring-data-relational/pom.xml b/spring-data-relational/pom.xml
index 9760a0f1e7..b3cd5bd55a 100644
--- a/spring-data-relational/pom.xml
+++ b/spring-data-relational/pom.xml
@@ -6,7 +6,7 @@
4.0.0
spring-data-relational
- 3.5.0-SNAPSHOT
+ 3.5.0-qbe-collections-SNAPSHOT
Spring Data Relational
Spring Data Relational support
@@ -14,7 +14,7 @@
org.springframework.data
spring-data-relational-parent
- 3.5.0-SNAPSHOT
+ 3.5.0-qbe-collections-SNAPSHOT
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/RelationalExampleMapper.java b/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/RelationalExampleMapper.java
index ce207e9e86..5bfd13f583 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/RelationalExampleMapper.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/RelationalExampleMapper.java
@@ -38,6 +38,7 @@
*
* @since 2.2
* @author Greg Turnquist
+ * @author Jens Schauder
*/
public class RelationalExampleMapper {
@@ -78,6 +79,10 @@ private Query getMappedExample(Example example, RelationalPersistentEntit
entity.doWithProperties((PropertyHandler) property -> {
+ if (property.isCollectionLike() || property.isMap()) {
+ return;
+ }
+
if (matcherAccessor.isIgnoredPath(property.getName())) {
return;
}
diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/repository/query/RelationalExampleMapperTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/repository/query/RelationalExampleMapperTests.java
index be447e4e44..963951c119 100644
--- a/spring-data-relational/src/test/java/org/springframework/data/relational/repository/query/RelationalExampleMapperTests.java
+++ b/spring-data-relational/src/test/java/org/springframework/data/relational/repository/query/RelationalExampleMapperTests.java
@@ -16,6 +16,15 @@
package org.springframework.data.relational.repository.query;
+import static org.assertj.core.api.Assertions.*;
+import static org.springframework.data.domain.ExampleMatcher.*;
+import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.*;
+import static org.springframework.data.domain.ExampleMatcher.StringMatcher.*;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.data.annotation.Id;
@@ -23,13 +32,7 @@
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.relational.core.query.Query;
-
-import java.util.Objects;
-
-import static org.assertj.core.api.Assertions.*;
-import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.*;
-import static org.springframework.data.domain.ExampleMatcher.StringMatcher.*;
-import static org.springframework.data.domain.ExampleMatcher.*;
+import org.springframework.lang.Nullable;
/**
* Verify that the {@link RelationalExampleMapper} properly turns {@link Example}s into {@link Query}'s.
@@ -48,8 +51,7 @@ public void before() {
@Test // GH-929
void queryByExampleWithId() {
- Person person = new Person();
- person.setId("id1");
+ Person person = new Person("id1", null, null, null, null, null);
Example example = Example.of(person);
@@ -63,8 +65,7 @@ void queryByExampleWithId() {
@Test // GH-929
void queryByExampleWithFirstname() {
- Person person = new Person();
- person.setFirstname("Frodo");
+ Person person = new Person(null, "Frodo", null, null, null, null);
Example example = Example.of(person);
@@ -78,9 +79,7 @@ void queryByExampleWithFirstname() {
@Test // GH-929
void queryByExampleWithFirstnameAndLastname() {
- Person person = new Person();
- person.setFirstname("Frodo");
- person.setLastname("Baggins");
+ Person person = new Person(null, "Frodo", "Baggins", null, null, null);
Example example = Example.of(person);
@@ -94,8 +93,7 @@ void queryByExampleWithFirstnameAndLastname() {
@Test // GH-929
void queryByExampleWithNullMatchingLastName() {
- Person person = new Person();
- person.setLastname("Baggins");
+ Person person = new Person(null, null, "Baggins", null, null, null);
ExampleMatcher matcher = matching().withIncludeNullValues();
Example example = Example.of(person, matcher);
@@ -110,9 +108,7 @@ void queryByExampleWithNullMatchingLastName() {
@Test // GH-929
void queryByExampleWithNullMatchingFirstnameAndLastname() {
- Person person = new Person();
- person.setFirstname("Bilbo");
- person.setLastname("Baggins");
+ Person person = new Person(null, "Bilbo", "Baggins", null, null, null);
ExampleMatcher matcher = matching().withIncludeNullValues();
Example example = Example.of(person, matcher);
@@ -127,9 +123,7 @@ void queryByExampleWithNullMatchingFirstnameAndLastname() {
@Test // GH-929
void queryByExampleWithFirstnameAndLastnameIgnoringFirstname() {
- Person person = new Person();
- person.setFirstname("Frodo");
- person.setLastname("Baggins");
+ Person person = new Person(null, "Bilbo", "Baggins", null, null, null);
ExampleMatcher matcher = matching().withIgnorePaths("firstname");
Example example = Example.of(person, matcher);
@@ -144,9 +138,7 @@ void queryByExampleWithFirstnameAndLastnameIgnoringFirstname() {
@Test // GH-929
void queryByExampleWithFirstnameAndLastnameWithNullMatchingIgnoringFirstName() {
- Person person = new Person();
- person.setFirstname("Frodo");
- person.setLastname("Baggins");
+ Person person = new Person(null, "Bilbo", "Baggins", null, null, null);
ExampleMatcher matcher = matching().withIncludeNullValues().withIgnorePaths("firstname");
Example example = Example.of(person, matcher);
@@ -161,8 +153,7 @@ void queryByExampleWithFirstnameAndLastnameWithNullMatchingIgnoringFirstName() {
@Test // GH-929
void queryByExampleWithFirstnameWithStringMatchingAtTheBeginning() {
- Person person = new Person();
- person.setFirstname("Fro");
+ Person person = new Person(null, "Fro", null, null, null, null);
ExampleMatcher matcher = matching().withStringMatcher(STARTING);
Example example = Example.of(person, matcher);
@@ -177,8 +168,7 @@ void queryByExampleWithFirstnameWithStringMatchingAtTheBeginning() {
@Test // GH-929
void queryByExampleWithFirstnameWithStringMatchingOnTheEnding() {
- Person person = new Person();
- person.setFirstname("do");
+ Person person = new Person(null, "do", null, null, null, null);
ExampleMatcher matcher = matching().withStringMatcher(ENDING);
Example example = Example.of(person, matcher);
@@ -193,8 +183,7 @@ void queryByExampleWithFirstnameWithStringMatchingOnTheEnding() {
@Test // GH-929
void queryByExampleWithFirstnameWithStringMatchingContaining() {
- Person person = new Person();
- person.setFirstname("do");
+ Person person = new Person(null, "do", null, null, null, null);
ExampleMatcher matcher = matching().withStringMatcher(CONTAINING);
Example example = Example.of(person, matcher);
@@ -209,8 +198,7 @@ void queryByExampleWithFirstnameWithStringMatchingContaining() {
@Test // GH-929
void queryByExampleWithFirstnameWithStringMatchingRegEx() {
- Person person = new Person();
- person.setFirstname("do");
+ Person person = new Person(null, "do", null, null, null, null);
ExampleMatcher matcher = matching().withStringMatcher(ExampleMatcher.StringMatcher.REGEX);
Example example = Example.of(person, matcher);
@@ -222,8 +210,7 @@ void queryByExampleWithFirstnameWithStringMatchingRegEx() {
@Test // GH-929
void queryByExampleWithFirstnameWithFieldSpecificStringMatcherEndsWith() {
- Person person = new Person();
- person.setFirstname("do");
+ Person person = new Person(null, "do", null, null, null, null);
ExampleMatcher matcher = matching().withMatcher("firstname", endsWith());
Example example = Example.of(person, matcher);
@@ -238,8 +225,7 @@ void queryByExampleWithFirstnameWithFieldSpecificStringMatcherEndsWith() {
@Test // GH-929
void queryByExampleWithFirstnameWithFieldSpecificStringMatcherStartsWith() {
- Person person = new Person();
- person.setFirstname("Fro");
+ Person person = new Person(null, "Fro", null, null, null, null);
ExampleMatcher matcher = matching().withMatcher("firstname", startsWith());
Example example = Example.of(person, matcher);
@@ -254,8 +240,7 @@ void queryByExampleWithFirstnameWithFieldSpecificStringMatcherStartsWith() {
@Test // GH-929
void queryByExampleWithFirstnameWithFieldSpecificStringMatcherContains() {
- Person person = new Person();
- person.setFirstname("do");
+ Person person = new Person(null, "do", null, null, null, null);
ExampleMatcher matcher = matching().withMatcher("firstname", contains());
Example example = Example.of(person, matcher);
@@ -270,8 +255,7 @@ void queryByExampleWithFirstnameWithFieldSpecificStringMatcherContains() {
@Test // GH-929
void queryByExampleWithFirstnameWithStringMatchingAtTheBeginningIncludingNull() {
- Person person = new Person();
- person.setFirstname("Fro");
+ Person person = new Person(null, "Fro", null, null, null, null);
ExampleMatcher matcher = matching().withStringMatcher(STARTING).withIncludeNullValues();
Example example = Example.of(person, matcher);
@@ -286,8 +270,7 @@ void queryByExampleWithFirstnameWithStringMatchingAtTheBeginningIncludingNull()
@Test // GH-929
void queryByExampleWithFirstnameWithStringMatchingOnTheEndingIncludingNull() {
- Person person = new Person();
- person.setFirstname("do");
+ Person person = new Person(null, "do", null, null, null, null);
ExampleMatcher matcher = matching().withStringMatcher(ENDING).withIncludeNullValues();
Example example = Example.of(person, matcher);
@@ -302,8 +285,7 @@ void queryByExampleWithFirstnameWithStringMatchingOnTheEndingIncludingNull() {
@Test // GH-929
void queryByExampleWithFirstnameIgnoreCaseFieldLevel() {
- Person person = new Person();
- person.setFirstname("fro");
+ Person person = new Person(null, "fro", null, null, null, null);
ExampleMatcher matcher = matching().withMatcher("firstname", startsWith().ignoreCase());
Example example = Example.of(person, matcher);
@@ -320,8 +302,7 @@ void queryByExampleWithFirstnameIgnoreCaseFieldLevel() {
@Test // GH-929
void queryByExampleWithFirstnameWithStringMatchingContainingIncludingNull() {
- Person person = new Person();
- person.setFirstname("do");
+ Person person = new Person(null, "do", null, null, null, null);
ExampleMatcher matcher = matching().withStringMatcher(CONTAINING).withIncludeNullValues();
Example example = Example.of(person, matcher);
@@ -336,8 +317,7 @@ void queryByExampleWithFirstnameWithStringMatchingContainingIncludingNull() {
@Test // GH-929
void queryByExampleWithFirstnameIgnoreCase() {
- Person person = new Person();
- person.setFirstname("Frodo");
+ Person person = new Person(null, "Frodo", null, null, null, null);
ExampleMatcher matcher = matching().withIgnoreCase(true);
Example example = Example.of(person, matcher);
@@ -354,9 +334,7 @@ void queryByExampleWithFirstnameIgnoreCase() {
@Test // GH-929
void queryByExampleWithFirstnameOrLastname() {
- Person person = new Person();
- person.setFirstname("Frodo");
- person.setLastname("Baggins");
+ Person person = new Person(null, "Frodo", "Baggins", null, null, null);
ExampleMatcher matcher = matchingAny();
Example example = Example.of(person, matcher);
@@ -371,9 +349,7 @@ void queryByExampleWithFirstnameOrLastname() {
@Test // GH-929
void queryByExampleEvenHandlesInvisibleFields() {
- Person person = new Person();
- person.setFirstname("Frodo");
- person.setSecret("I have the ring!");
+ Person person = new Person(null, "Frodo", null, "I have the ring!", null, null);
Example example = Example.of(person);
@@ -388,10 +364,7 @@ void queryByExampleEvenHandlesInvisibleFields() {
@Test // GH-929
void queryByExampleSupportsPropertyTransforms() {
- Person person = new Person();
- person.setFirstname("Frodo");
- person.setLastname("Baggins");
- person.setSecret("I have the ring!");
+ Person person = new Person(null, "Frodo", "Baggins", "I have the ring!", null, null);
ExampleMatcher matcher = matching() //
.withTransformer("firstname", o -> {
@@ -418,55 +391,33 @@ void queryByExampleSupportsPropertyTransforms() {
"(secret = 'I have the ring!')");
}
- static class Person {
+ @Test // GH-1969
+ void collectionLikeAttributesGetIgnored() {
- @Id
- String id;
- String firstname;
- String lastname;
- String secret;
+ Example example = Example.of(new Person(null, "Frodo", null, null, List.of(new Possession("Ring")), null));
- public Person(String id, String firstname, String lastname, String secret) {
- this.id = id;
- this.firstname = firstname;
- this.lastname = lastname;
- this.secret = secret;
- }
-
- public Person() {
- }
+ Query query = exampleMapper.getMappedExample(example);
- // Override default visibility of getting the secret.
- private String getSecret() {
- return this.secret;
- }
+ assertThat(query.getCriteria().orElseThrow().toString()).doesNotContainIgnoringCase("possession");
+ }
- public String getId() {
- return this.id;
- }
+ @Test // GH-1969
+ void mapAttributesGetIgnored() {
- public String getFirstname() {
- return this.firstname;
- }
+ Example example = Example.of(new Person(null, "Frodo", null, null, null, Map.of("Home", new Address("Bag End"))));
- public String getLastname() {
- return this.lastname;
- }
+ Query query = exampleMapper.getMappedExample(example);
- public void setId(String id) {
- this.id = id;
- }
+ assertThat(query.getCriteria().orElseThrow().toString()).doesNotContainIgnoringCase("address");
+ }
- public void setFirstname(String firstname) {
- this.firstname = firstname;
- }
+ record Person(@Id @Nullable String id, @Nullable String firstname, @Nullable String lastname, @Nullable String secret,
+ @Nullable List possessions,@Nullable Map addresses) {
+ }
- public void setLastname(String lastname) {
- this.lastname = lastname;
- }
+ record Possession(String name) {
+ }
- public void setSecret(String secret) {
- this.secret = secret;
- }
+ record Address(String description) {
}
}
diff --git a/src/main/antora/modules/ROOT/pages/query-by-example.adoc b/src/main/antora/modules/ROOT/pages/query-by-example.adoc
index b8c3c9a140..491c57ca0b 100644
--- a/src/main/antora/modules/ROOT/pages/query-by-example.adoc
+++ b/src/main/antora/modules/ROOT/pages/query-by-example.adoc
@@ -1,3 +1,4 @@
+:support-qbe-collection: false
include::{commons}@data-commons::query-by-example.adoc[]
Here's an example: