Skip to content

Commit 9fc36ef

Browse files
committed
Check for page offsets exceeding Integer.MAX_VALUE.
Instead of relying on the JPA provider to handle page offsets exceeding Integer.MAX_VALUE, do the check inside Spring Data JPA and provide a more meaningful error message. Closes #2502.
1 parent 6be9b14 commit 9fc36ef

File tree

5 files changed

+61
-11
lines changed

5 files changed

+61
-11
lines changed

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import jakarta.persistence.Query;
1919

2020
import org.springframework.data.jpa.repository.query.QueryParameterSetter.ErrorHandling;
21+
import org.springframework.data.jpa.support.PageableUtils;
2122
import org.springframework.util.Assert;
2223

2324
/**
@@ -99,7 +100,7 @@ Query bindAndPrepare(Query query, QueryParameterSetter.QueryMetadata metadata,
99100
return query;
100101
}
101102

102-
query.setFirstResult((int) accessor.getPageable().getOffset());
103+
query.setFirstResult(PageableUtils.getOffsetAsInteger(accessor.getPageable()));
103104
query.setMaxResults(accessor.getPageable().getPageSize());
104105

105106
return query;

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryByExample.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,24 @@
1515
*/
1616
package org.springframework.data.jpa.repository.support;
1717

18+
import jakarta.persistence.EntityManager;
19+
import jakarta.persistence.TypedQuery;
20+
1821
import java.util.ArrayList;
1922
import java.util.Collection;
2023
import java.util.Collections;
2124
import java.util.List;
2225
import java.util.function.Function;
2326
import java.util.stream.Stream;
2427

25-
import jakarta.persistence.EntityManager;
26-
import jakarta.persistence.TypedQuery;
27-
2828
import org.springframework.dao.IncorrectResultSizeDataAccessException;
2929
import org.springframework.data.domain.Example;
3030
import org.springframework.data.domain.Page;
3131
import org.springframework.data.domain.PageImpl;
3232
import org.springframework.data.domain.Pageable;
3333
import org.springframework.data.domain.Sort;
3434
import org.springframework.data.jpa.repository.query.EscapeCharacter;
35+
import org.springframework.data.jpa.support.PageableUtils;
3536
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
3637
import org.springframework.data.support.PageableExecutionUtils;
3738
import org.springframework.util.Assert;
@@ -66,8 +67,7 @@ public FetchableFluentQueryByExample(Example<S> example, Function<Sort, TypedQue
6667

6768
private FetchableFluentQueryByExample(Example<S> example, Class<S> entityType, Class<R> returnType, Sort sort,
6869
Collection<String> properties, Function<Sort, TypedQuery<S>> finder, Function<Example<S>, Long> countOperation,
69-
Function<Example<S>, Boolean> existsOperation,
70-
EntityManager entityManager, EscapeCharacter escapeCharacter) {
70+
Function<Example<S>, Boolean> existsOperation, EntityManager entityManager, EscapeCharacter escapeCharacter) {
7171

7272
super(returnType, sort, properties, entityType);
7373
this.example = example;
@@ -83,8 +83,8 @@ public FetchableFluentQuery<R> sortBy(Sort sort) {
8383

8484
Assert.notNull(sort, "Sort must not be null!");
8585

86-
return new FetchableFluentQueryByExample<>(example, entityType, resultType, this.sort.and(sort), properties,
87-
finder, countOperation, existsOperation, entityManager, escapeCharacter);
86+
return new FetchableFluentQueryByExample<>(example, entityType, resultType, this.sort.and(sort), properties, finder,
87+
countOperation, existsOperation, entityManager, escapeCharacter);
8888
}
8989

9090
@Override
@@ -168,7 +168,7 @@ private Page<R> readPage(Pageable pageable) {
168168
TypedQuery<S> pagedQuery = createSortedAndProjectedQuery();
169169

170170
if (pageable.isPaged()) {
171-
pagedQuery.setFirstResult((int) pageable.getOffset());
171+
pagedQuery.setFirstResult(PageableUtils.getOffsetAsInteger(pageable));
172172
pagedQuery.setMaxResults(pageable.getPageSize());
173173
}
174174

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryBySpecification.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.springframework.data.domain.Pageable;
3232
import org.springframework.data.domain.Sort;
3333
import org.springframework.data.jpa.domain.Specification;
34+
import org.springframework.data.jpa.support.PageableUtils;
3435
import org.springframework.data.repository.query.FluentQuery;
3536
import org.springframework.data.support.PageableExecutionUtils;
3637
import org.springframework.util.Assert;
@@ -170,7 +171,7 @@ private Page<R> readPage(Pageable pageable) {
170171
TypedQuery<S> pagedQuery = createSortedAndProjectedQuery();
171172

172173
if (pageable.isPaged()) {
173-
pagedQuery.setFirstResult((int) pageable.getOffset());
174+
pagedQuery.setFirstResult(PageableUtils.getOffsetAsInteger(pageable));
174175
pagedQuery.setMaxResults(pageable.getPageSize());
175176
}
176177

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import org.springframework.data.jpa.repository.query.EscapeCharacter;
5656
import org.springframework.data.jpa.repository.query.QueryUtils;
5757
import org.springframework.data.jpa.repository.support.QueryHints.NoHints;
58+
import org.springframework.data.jpa.support.PageableUtils;
5859
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
5960
import org.springframework.data.support.PageableExecutionUtils;
6061
import org.springframework.data.util.ProxyUtils;
@@ -650,7 +651,7 @@ protected <S extends T> Page<S> readPage(TypedQuery<S> query, final Class<S> dom
650651
@Nullable Specification<S> spec) {
651652

652653
if (pageable.isPaged()) {
653-
query.setFirstResult((int) pageable.getOffset());
654+
query.setFirstResult(PageableUtils.getOffsetAsInteger(pageable));
654655
query.setMaxResults(pageable.getPageSize());
655656
}
656657

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2008-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jpa.support;
17+
18+
import org.springframework.dao.InvalidDataAccessApiUsageException;
19+
import org.springframework.data.domain.Pageable;
20+
21+
/**
22+
* Provide a set of utility methods to support interfacing {@link Pageable}s.
23+
*
24+
* @author Greg Turnquist
25+
* @since 3.0
26+
*/
27+
public final class PageableUtils {
28+
29+
private PageableUtils() {
30+
throw new IllegalStateException("Cannot instantiate a utility class!");
31+
}
32+
33+
/**
34+
* Convert a {@link Pageable}'s offset value from {@link Long} to {@link Integer} to support JPA spec methods.
35+
*
36+
* @param pageable
37+
* @return integer
38+
*/
39+
public static int getOffsetAsInteger(Pageable pageable) {
40+
41+
if (pageable.getOffset() > Integer.MAX_VALUE) {
42+
throw new InvalidDataAccessApiUsageException("Page offset exceeds Integer.MAX_VALUE (" + Integer.MAX_VALUE + ")");
43+
}
44+
45+
return Math.toIntExact(pageable.getOffset());
46+
}
47+
}

0 commit comments

Comments
 (0)