Skip to content

Commit 93899f7

Browse files
committed
DATACMNS-377 - Prevent page sizes less than one.
PageRequest now actively prevents page sizes less than one. PageableHandlerMethodArgumentResolver falls back to default page size if it detects a page size less than one. It also rejects invalid default configuration using @PageableDefault.
1 parent 5b72373 commit 93899f7

File tree

4 files changed

+67
-8
lines changed

4 files changed

+67
-8
lines changed

src/main/java/org/springframework/data/domain/PageRequest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ public PageRequest(int page, int size, Sort sort) {
6868
throw new IllegalArgumentException("Page index must not be less than zero!");
6969
}
7070

71-
if (size < 0) {
72-
throw new IllegalArgumentException("Page size must not be less than zero!");
71+
if (size < 1) {
72+
throw new IllegalArgumentException("Page size must not be less than one!");
7373
}
7474

7575
this.page = page;

src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolver.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
import static org.springframework.data.web.SpringDataAnnotationUtils.*;
1919

20+
import java.lang.reflect.Method;
21+
2022
import org.springframework.beans.factory.annotation.Qualifier;
2123
import org.springframework.core.MethodParameter;
2224
import org.springframework.data.domain.PageRequest;
@@ -41,6 +43,8 @@
4143
@SuppressWarnings("deprecation")
4244
public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
4345

46+
private static final String INVALID_DEFAULT_PAGE_SIZE = "Invalid default page size configured for method %s! Must not be less than one!";
47+
4448
/**
4549
* A {@link PageableHandlerMethodArgumentResolver} preconfigured to the setup of {@link PageableArgumentResolver}. Use
4650
* that if you need to stick to the former request parameters an 1-indexed behavior. This will be removed in the next
@@ -58,12 +62,12 @@ public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgum
5862
LEGACY.sortResolver.setSortParameter("page.sort");
5963
}
6064

61-
private static final Pageable DEFAULT_PAGE_REQUEST = new PageRequest(0, 20);
6265
private static final String DEFAULT_PAGE_PARAMETER = "page";
6366
private static final String DEFAULT_SIZE_PARAMETER = "size";
6467
private static final String DEFAULT_PREFIX = "";
6568
private static final String DEFAULT_QUALIFIER_DELIMITER = "_";
6669
private static final int DEFAULT_MAX_PAGE_SIZE = 2000;
70+
static final Pageable DEFAULT_PAGE_REQUEST = new PageRequest(0, 20);
6771

6872
private Pageable fallbackPageable = DEFAULT_PAGE_REQUEST;
6973
private SortHandlerMethodArgumentResolver sortResolver;
@@ -234,6 +238,10 @@ public Pageable resolveArgument(MethodParameter methodParameter, ModelAndViewCon
234238
: defaultOrFallback.getPageNumber();
235239
int pageSize = StringUtils.hasText(pageSizeString) ? Integer.parseInt(pageSizeString) : defaultOrFallback
236240
.getPageSize();
241+
242+
// Limit lower bound
243+
pageSize = pageSize < 1 ? defaultOrFallback.getPageSize() : pageSize;
244+
// Limit upper bound
237245
pageSize = pageSize > maxPageSize ? maxPageSize : pageSize;
238246

239247
Sort sort = sortResolver.resolveArgument(methodParameter, mavContainer, webRequest, binderFactory);
@@ -269,17 +277,24 @@ private Pageable getDefaultFromAnnotationOrFallback(MethodParameter methodParame
269277
}
270278

271279
if (methodParameter.hasParameterAnnotation(PageableDefault.class)) {
272-
return getDefaultPageRequestFrom(methodParameter.getParameterAnnotation(PageableDefault.class));
280+
return getDefaultPageRequestFrom(methodParameter);
273281
}
274282

275283
return fallbackPageable;
276284
}
277285

278-
private static Pageable getDefaultPageRequestFrom(PageableDefault defaults) {
286+
private static Pageable getDefaultPageRequestFrom(MethodParameter parameter) {
287+
288+
PageableDefault defaults = parameter.getParameterAnnotation(PageableDefault.class);
279289

280290
Integer defaultPageNumber = defaults.page();
281291
Integer defaultPageSize = getSpecificPropertyOrDefaultFromValue(defaults, "size");
282292

293+
if (defaultPageSize < 1) {
294+
Method annotatedMethod = parameter.getMethod();
295+
throw new IllegalStateException(String.format(INVALID_DEFAULT_PAGE_SIZE, annotatedMethod));
296+
}
297+
283298
if (defaults.sort().length == 0) {
284299
return new PageRequest(defaultPageNumber, defaultPageSize);
285300
}

src/test/java/org/springframework/data/domain/PageRequestUnitTests.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,12 @@ public void equalsHonoursPageAndSize() {
9494
// Does not equal on different size
9595
assertNotEqualsAndHashcode(request, new PageRequest(0, 11));
9696
}
97+
98+
/**
99+
* @see DATACMNS-377
100+
*/
101+
@Test(expected = IllegalArgumentException.class)
102+
public void preventsPageSizeLessThanOne() {
103+
new PageRequest(0, 0);
104+
}
97105
}

src/test/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverUnitTests.java

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.data.web;
1717

18+
import org.junit.Before;
1819
import org.junit.Test;
1920
import org.springframework.beans.factory.annotation.Qualifier;
2021
import org.springframework.core.MethodParameter;
@@ -33,6 +34,13 @@
3334
*/
3435
public class PageableHandlerMethodArgumentResolverUnitTests extends PageableDefaultUnitTests {
3536

37+
MethodParameter supportedMethodParameter;
38+
39+
@Before
40+
public void setUp() throws Exception {
41+
this.supportedMethodParameter = new MethodParameter(Sample.class.getMethod("supportedMethod", Pageable.class), 0);
42+
}
43+
3644
/**
3745
* @see DATACMNS-335
3846
*/
@@ -44,9 +52,7 @@ public void preventsPageSizeFromExceedingMayValueIfConfigured() throws Exception
4452
request.addParameter("page", "0");
4553
request.addParameter("size", "200");
4654

47-
MethodParameter parameter = new MethodParameter(Sample.class.getMethod("supportedMethod", Pageable.class), 0);
48-
49-
assertSupportedAndResult(parameter, new PageRequest(0, 100), request);
55+
assertSupportedAndResult(supportedMethodParameter, new PageRequest(0, 100), request);
5056
}
5157

5258
@Test(expected = IllegalArgumentException.class)
@@ -81,6 +87,34 @@ public void qualifierIsUsedInParameterLookup() throws Exception {
8187
assertSupportedAndResult(parameter, new PageRequest(2, 10), request);
8288
}
8389

90+
/**
91+
* @see DATACMNS-377
92+
*/
93+
@Test
94+
public void usesDefaultPageSizeIfRequestPageSizeIsLessThanOne() throws Exception {
95+
96+
MockHttpServletRequest request = new MockHttpServletRequest();
97+
request.addParameter("page", "0");
98+
request.addParameter("size", "0");
99+
100+
assertSupportedAndResult(supportedMethodParameter, PageableHandlerMethodArgumentResolver.DEFAULT_PAGE_REQUEST,
101+
request);
102+
}
103+
104+
/**
105+
* @see DATACMNS-377
106+
*/
107+
@Test
108+
public void rejectsInvalidCustomDefaultForPageSize() throws Exception {
109+
110+
MethodParameter parameter = new MethodParameter(Sample.class.getMethod("invalidDefaultPageSize", Pageable.class), 0);
111+
112+
exception.expect(IllegalStateException.class);
113+
exception.expectMessage("invalidDefaultPageSize");
114+
115+
assertSupportedAndResult(parameter, PageableHandlerMethodArgumentResolver.DEFAULT_PAGE_REQUEST);
116+
}
117+
84118
@Override
85119
protected PageableHandlerMethodArgumentResolver getResolver() {
86120
PageableHandlerMethodArgumentResolver resolver = new PageableHandlerMethodArgumentResolver();
@@ -99,6 +133,8 @@ interface Sample {
99133

100134
void unsupportedMethod(String string);
101135

136+
void invalidDefaultPageSize(@PageableDefault(size = 0) Pageable pageable);
137+
102138
void simpleDefault(@PageableDefault(size = PAGE_SIZE, page = PAGE_NUMBER) Pageable pageable);
103139

104140
void simpleDefaultWithSort(@PageableDefault(size = PAGE_SIZE, page = PAGE_NUMBER,

0 commit comments

Comments
 (0)