diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java index 25f6cff81..dfd0dabce 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java @@ -30,6 +30,7 @@ import org.springframework.util.Assert; * @author Mark Paluch * @author Christoph Strobl * @author Jens Schauder + * @author Yanming Zhou */ public class ParameterBinder { @@ -101,7 +102,11 @@ public class ParameterBinder { return query; } - query.setFirstResult(PageableUtils.getOffsetAsInteger(accessor.getPageable())); + // see #3242 + if (!parameters.hasLimitParameter()) { + // offset is meaningless if Limit parameter present + query.setFirstResult(PageableUtils.getOffsetAsInteger(accessor.getPageable())); + } query.setMaxResults(accessor.getPageable().getPageSize()); return query; diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterBinderUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterBinderUnitTests.java index e62dc25bc..3cd30f291 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterBinderUnitTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterBinderUnitTests.java @@ -39,6 +39,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; +import org.springframework.data.domain.Limit; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.repository.Temporal; @@ -53,6 +54,7 @@ import org.springframework.data.repository.query.ParametersSource; * @author Thomas Darimont * @author Jens Schauder * @author Mark Paluch + * @author Yanming Zhou */ @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) @@ -86,6 +88,8 @@ class ParameterBinderUnitTests { User validWithPageable(@Param("username") String username, Pageable pageable); + User validWithLimit(@Param("username") String username, Limit limit); + User validWithSort(@Param("username") String username, Sort sort); User validWithDefaultTemporalTypeParameter(@Temporal Date registerDate); @@ -122,6 +126,40 @@ class ParameterBinderUnitTests { verify(query).setParameter(eq(1), eq("foo")); } + @Test + void bindAndPrepareWorksWithPageable() throws Exception { + + Method validWithPageable = SampleRepository.class.getMethod("validWithPageable", String.class, Pageable.class); + + Object[] values = { "foo", Pageable.ofSize(10).withPage(3) }; + bindAndPrepare(validWithPageable, values); + verify(query).setParameter(eq(1), eq("foo")); + verify(query).setFirstResult(eq(30)); + verify(query).setMaxResults(eq(10)); + } + + @Test + void bindWorksWithNullForLimit() throws Exception { + + Method validWithLimit = SampleRepository.class.getMethod("validWithLimit", String.class, Limit.class); + + Object[] values = { "foo", null }; + bind(validWithLimit, values); + verify(query).setParameter(eq(1), eq("foo")); + } + + @Test + void bindAndPrepareWorksWithLimit() throws Exception { + + Method validWithLimit = SampleRepository.class.getMethod("validWithLimit", String.class, Limit.class); + + Object[] values = { "foo", Limit.of(10) }; + bindAndPrepare(validWithLimit, values); + verify(query).setParameter(eq(1), eq("foo")); + verify(query).setMaxResults(eq(10)); + verify(query, never()).setFirstResult(anyInt()); + } + @Test void usesIndexedParametersIfNoParamAnnotationPresent() { @@ -236,6 +274,11 @@ class ParameterBinderUnitTests { getAccessor(method, values), QueryParameterSetter.ErrorHandling.STRICT); } + private void bindAndPrepare(Method method, Object[] values) { + ParameterBinderFactory.createBinder(createParameters(method)).bindAndPrepare(query, + new QueryParameterSetter.QueryMetadata(query), getAccessor(method, values)); + } + private JpaParametersParameterAccessor getAccessor(Method method, Object... values) { return new JpaParametersParameterAccessor(createParameters(method), values); }