diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryByPredicate.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryByPredicate.java index 61268e6087..b70b3b4d42 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryByPredicate.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryByPredicate.java @@ -15,6 +15,8 @@ */ package org.springframework.data.jpa.repository.support; +import jakarta.persistence.EntityManager; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -23,8 +25,6 @@ import java.util.function.Function; import java.util.stream.Stream; -import jakarta.persistence.EntityManager; - import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; @@ -69,8 +69,7 @@ public FetchableFluentQueryByPredicate(Predicate predicate, Class entityType, private FetchableFluentQueryByPredicate(Predicate predicate, Class entityType, Class resultType, Sort sort, Collection properties, Function> finder, BiFunction> pagedFinder, Function countOperation, - Function existsOperation, - EntityManager entityManager) { + Function existsOperation, EntityManager entityManager) { super(resultType, sort, properties, entityType); this.predicate = predicate; @@ -175,8 +174,13 @@ public boolean exists() { private Page readPage(Pageable pageable) { - AbstractJPAQuery pagedQuery = pagedFinder.apply(sort, pageable); - List paginatedResults = convert(pagedQuery.fetch()); + AbstractJPAQuery query = pagedFinder.apply(sort, pageable); + + if (!properties.isEmpty()) { + query.setHint(EntityGraphFactory.HINT, EntityGraphFactory.create(entityManager, entityType, properties)); + } + + List paginatedResults = convert(query.fetch()); return PageableExecutionUtils.getPage(paginatedResults, pageable, () -> countOperation.apply(predicate)); } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java index b912aa2aaa..cb27a695f3 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java @@ -15,14 +15,13 @@ */ package org.springframework.data.jpa.repository; -import static java.util.Arrays.asList; +import static java.util.Arrays.*; import static org.assertj.core.api.Assertions.*; -import static org.springframework.data.domain.Example.of; +import static org.springframework.data.domain.Example.*; import static org.springframework.data.domain.ExampleMatcher.*; -import static org.springframework.data.domain.Sort.Direction.ASC; -import static org.springframework.data.domain.Sort.Direction.DESC; +import static org.springframework.data.domain.Sort.Direction.*; +import static org.springframework.data.jpa.domain.Specification.*; import static org.springframework.data.jpa.domain.Specification.not; -import static org.springframework.data.jpa.domain.Specification.where; import static org.springframework.data.jpa.domain.sample.UserSpecifications.*; import jakarta.persistence.EntityManager; @@ -53,6 +52,7 @@ import org.springframework.data.domain.Sort.Order; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.sample.Address; +import org.springframework.data.jpa.domain.sample.QUser; import org.springframework.data.jpa.domain.sample.Role; import org.springframework.data.jpa.domain.sample.SpecialUser; import org.springframework.data.jpa.domain.sample.User; @@ -2421,6 +2421,47 @@ void findByFluentSpecificationWithSimplePropertyPathsDoesntLoadUnrequestedPaths( ); } + @Test // GH-2820 + void findByFluentPredicateWithProjectionAndPageRequest() { + + flushTestUsers(); + em.clear(); + + Page users = repository.findBy(QUser.user.firstname.contains("v"), q -> q // + .project("firstname") // + .page(PageRequest.of(0, 10))); + + assertThat(users).extracting(User::getFirstname).containsExactlyInAnyOrder(firstUser.getFirstname(), + thirdUser.getFirstname(), fourthUser.getFirstname()); + } + + @Test // GH-2820 + void findByFluentPredicateWithProjectionAndAll() { + + flushTestUsers(); + em.clear(); + + List users = repository.findBy(QUser.user.firstname.contains("v"), q -> q // + .project("firstname") // + .all()); + + assertThat(users).extracting(User::getFirstname).containsExactlyInAnyOrder(firstUser.getFirstname(), + thirdUser.getFirstname(), fourthUser.getFirstname()); + } + + @Test // GH-2820 + void findByFluentPredicateWithPageRequest() { + + flushTestUsers(); + em.clear(); + + Page users = repository.findBy(QUser.user.firstname.contains("v"), q -> q // + .page(PageRequest.of(0, 10))); + + assertThat(users).extracting(User::getFirstname).containsExactlyInAnyOrder(firstUser.getFirstname(), + thirdUser.getFirstname(), fourthUser.getFirstname()); + } + @Test // GH-2274 void findByFluentSpecificationWithCollectionPropertyPathsDoesntLoadUnrequestedPaths() { 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 6ff229d87c..ed5fcdbac5 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 @@ -18,15 +18,29 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.QueryHint; -import java.util.*; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.stream.Stream; -import org.springframework.data.domain.*; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.sample.Role; import org.springframework.data.jpa.domain.sample.SpecialUser; import org.springframework.data.jpa.domain.sample.User; -import org.springframework.data.jpa.repository.*; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.jpa.repository.QueryHints; import org.springframework.data.jpa.repository.query.Procedure; +import org.springframework.data.querydsl.ListQuerydslPredicateExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.transaction.annotation.Transactional; @@ -45,8 +59,8 @@ * @author Diego Krupitza * @author Geoffrey Deremetz */ -public interface UserRepository - extends JpaRepository, JpaSpecificationExecutor, UserRepositoryCustom { +public interface UserRepository extends JpaRepository, JpaSpecificationExecutor, + UserRepositoryCustom, ListQuerydslPredicateExecutor { /** * Retrieve users by their lastname. The finder {@literal User.findByLastname} is declared in diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanEntityPathResolverIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanEntityPathResolverIntegrationTests.java index 345a71e15d..76e83da05a 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanEntityPathResolverIntegrationTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanEntityPathResolverIntegrationTests.java @@ -32,8 +32,6 @@ import org.springframework.data.querydsl.SimpleEntityPathResolver; import org.springframework.test.util.ReflectionTestUtils; -import com.querydsl.core.types.EntityPath; - /** * Unit tests for {@link EntityPathResolver} related tests on {@link JpaRepositoryFactoryBean}. * @@ -47,14 +45,7 @@ class JpaRepositoryFactoryBeanEntityPathResolverIntegrationTests { @EnableJpaRepositories(basePackageClasses = UserRepository.class, // includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = UserRepository.class)) static class BaseConfig { - - static final EntityPathResolver RESOLVER = new EntityPathResolver() { - - @Override - public EntityPath createPath(Class domainClass) { - return null; - } - }; + static final EntityPathResolver RESOLVER = SimpleEntityPathResolver.INSTANCE; } @Configuration