From 0c90ff375905dd742d382a1780bb6efc529137a5 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 12 Apr 2023 11:32:20 +0200 Subject: [PATCH] Adopt to changed Hibernate behavior returning domain types using tuple queries. We now allow using the domain type when it is returned from a tuple query. This allows projections if the return value is not a Map. Closes #2815 --- .../repository/query/AbstractJpaQuery.java | 5 ++-- .../repository/UserRepositoryFinderTests.java | 23 +++++++++++++++++-- .../jpa/repository/sample/UserRepository.java | 7 ++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java index 70ec15d0e..7e70d350f 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java @@ -314,18 +314,17 @@ public abstract class AbstractJpaQuery implements RepositoryQuery { @Override public Object convert(Object source) { - if (!(source instanceof Tuple)) { + if (!(source instanceof Tuple tuple)) { return source; } - Tuple tuple = (Tuple) source; List> elements = tuple.getElements(); if (elements.size() == 1) { Object value = tuple.get(elements.get(0)); - if (type.isInstance(value) || value == null) { + if (type.getDomainType().isInstance(value) || type.isInstance(value) || value == null) { return value; } } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java index 4d5522244..6fa3e2b00 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java @@ -40,6 +40,8 @@ import org.springframework.data.jpa.domain.sample.User; import org.springframework.data.jpa.provider.PersistenceProvider; import org.springframework.data.jpa.repository.sample.RoleRepository; import org.springframework.data.jpa.repository.sample.UserRepository; +import org.springframework.data.jpa.repository.sample.UserRepository.IdOnly; +import org.springframework.data.jpa.repository.sample.UserRepository.RolesAndFirstname; import org.springframework.data.repository.query.QueryLookupStrategy; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -281,11 +283,28 @@ class UserRepositoryFinderTests { .containsExactlyInAnyOrder(dave, oliver); } - @Test // DATAJPA-974 + @Test // DATAJPA-974, GH-2815 void executesQueryWithProjectionContainingReferenceToPluralAttribute() { - assertThat(userRepository.findRolesAndFirstnameBy()) // + List rolesAndFirstnameBy = userRepository.findRolesAndFirstnameBy(); + + assertThat(rolesAndFirstnameBy) .isNotNull(); + + for (RolesAndFirstname rolesAndFirstname : rolesAndFirstnameBy) { + assertThat(rolesAndFirstname.getFirstname()).isNotNull(); + assertThat(rolesAndFirstname.getRoles()).isNotNull(); + } + } + + @Test // GH-2815 + void executesQueryWithProjectionThroughStringQuery() { + + List ids = userRepository.findIdOnly(); + + assertThat(ids).isNotNull(); + + assertThat(ids).extracting(IdOnly::getId).doesNotContainNull(); } @Test // DATAJPA-1023, DATACMNS-959 diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java index 24362a2a7..5eb749039 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java @@ -556,6 +556,9 @@ public interface UserRepository extends JpaRepository, JpaSpecifi List findRolesAndFirstnameBy(); + @Query(value = "FROM User u") + List findIdOnly(); + // DATAJPA-1172 @Query("select u from User u where u.age = :age") List findByStringAge(@Param("age") String age); @@ -732,4 +735,8 @@ public interface UserRepository extends JpaRepository, JpaSpecifi interface EmailOnly { String getEmailAddress(); } + + interface IdOnly { + int getId(); + } }