Skip to content

Commit cc4a4de

Browse files
committed
DATACMNS-408 - Handle invalid pagination and sorting parameters gracefully.
The PageableHandlerMethodArgumentResolver and SortHandlerMethodArgumentResolver now transparently ignore invalid values provided for page number, size and sort. We fall back to ignore the invalid values (for sort) and fall back to the defaults where appropriate (page number and size). Used and adapted test cases from pull request #48.
1 parent 62e14d2 commit cc4a4de

File tree

4 files changed

+136
-8
lines changed

4 files changed

+136
-8
lines changed

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

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -234,10 +234,10 @@ public Pageable resolveArgument(MethodParameter methodParameter, ModelAndViewCon
234234
String pageString = webRequest.getParameter(getParameterNameToUse(pageParameterName, methodParameter));
235235
String pageSizeString = webRequest.getParameter(getParameterNameToUse(sizeParameterName, methodParameter));
236236

237-
int page = StringUtils.hasText(pageString) ? Integer.parseInt(pageString) - (oneIndexedParameters ? 1 : 0)
238-
: defaultOrFallback.getPageNumber();
239-
int pageSize = StringUtils.hasText(pageSizeString) ? Integer.parseInt(pageSizeString) : defaultOrFallback
240-
.getPageSize();
237+
int page = StringUtils.hasText(pageString) ? parseAndApplyBoundaries(pageString, 0, Integer.MAX_VALUE)
238+
- (oneIndexedParameters ? 1 : 0) : defaultOrFallback.getPageNumber();
239+
int pageSize = StringUtils.hasText(pageSizeString) ? parseAndApplyBoundaries(pageSizeString, 0, maxPageSize)
240+
: defaultOrFallback.getPageSize();
241241

242242
// Limit lower bound
243243
pageSize = pageSize < 1 ? defaultOrFallback.getPageSize() : pageSize;
@@ -301,4 +301,23 @@ private static Pageable getDefaultPageRequestFrom(MethodParameter parameter) {
301301

302302
return new PageRequest(defaultPageNumber, defaultPageSize, defaults.direction(), defaults.sort());
303303
}
304+
305+
/**
306+
* Tries to parse the given {@link String} into an integer and applies the given boundaries. Will return the lower
307+
* boundary if the {@link String} cannot be parsed.
308+
*
309+
* @param parameter
310+
* @param lower
311+
* @param upper
312+
* @return
313+
*/
314+
private static int parseAndApplyBoundaries(String parameter, int lower, int upper) {
315+
316+
try {
317+
int parsed = Integer.parseInt(parameter);
318+
return parsed < lower ? lower : parsed > upper ? upper : parsed;
319+
} catch (NumberFormatException e) {
320+
return lower;
321+
}
322+
}
304323
}

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,13 @@ Sort parseParameterIntoSort(String[] source, String delimiter) {
251251
continue;
252252
}
253253

254-
allOrders.add(new Order(direction, elements[i]));
254+
String property = elements[i];
255+
256+
if (!StringUtils.hasText(property)) {
257+
continue;
258+
}
259+
260+
allOrders.add(new Order(direction, property));
255261
}
256262
}
257263

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

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

18+
import static org.springframework.data.web.PageableHandlerMethodArgumentResolver.*;
19+
1820
import org.junit.Before;
1921
import org.junit.Test;
2022
import org.springframework.beans.factory.annotation.Qualifier;
@@ -97,8 +99,7 @@ public void usesDefaultPageSizeIfRequestPageSizeIsLessThanOne() throws Exception
9799
request.addParameter("page", "0");
98100
request.addParameter("size", "0");
99101

100-
assertSupportedAndResult(supportedMethodParameter, PageableHandlerMethodArgumentResolver.DEFAULT_PAGE_REQUEST,
101-
request);
102+
assertSupportedAndResult(supportedMethodParameter, DEFAULT_PAGE_REQUEST, request);
102103
}
103104

104105
/**
@@ -112,7 +113,43 @@ public void rejectsInvalidCustomDefaultForPageSize() throws Exception {
112113
exception.expect(IllegalStateException.class);
113114
exception.expectMessage("invalidDefaultPageSize");
114115

115-
assertSupportedAndResult(parameter, PageableHandlerMethodArgumentResolver.DEFAULT_PAGE_REQUEST);
116+
assertSupportedAndResult(parameter, DEFAULT_PAGE_REQUEST);
117+
}
118+
119+
/**
120+
* @see DATACMNS-408
121+
*/
122+
@Test
123+
public void fallsBackToFirstPageIfNegativePageNumberIsGiven() throws Exception {
124+
125+
MockHttpServletRequest request = new MockHttpServletRequest();
126+
request.addParameter("page", "-1");
127+
128+
assertSupportedAndResult(supportedMethodParameter, DEFAULT_PAGE_REQUEST, request);
129+
}
130+
131+
/**
132+
* @see DATACMNS-408
133+
*/
134+
@Test
135+
public void pageParamIsNotNumeric() throws Exception {
136+
137+
MockHttpServletRequest request = new MockHttpServletRequest();
138+
request.addParameter("page", "a");
139+
140+
assertSupportedAndResult(supportedMethodParameter, DEFAULT_PAGE_REQUEST, request);
141+
}
142+
143+
/**
144+
* @see DATACMNS-408
145+
*/
146+
@Test
147+
public void sizeParamIsNotNumeric() throws Exception {
148+
149+
MockHttpServletRequest request = new MockHttpServletRequest();
150+
request.addParameter("size", "a");
151+
152+
assertSupportedAndResult(supportedMethodParameter, DEFAULT_PAGE_REQUEST, request);
116153
}
117154

118155
@Override

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

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717

1818
import static org.hamcrest.CoreMatchers.*;
1919
import static org.junit.Assert.*;
20+
import static org.springframework.data.domain.Sort.Direction.*;
2021

22+
import javax.servlet.http.HttpServletRequest;
23+
24+
import org.junit.BeforeClass;
2125
import org.junit.Test;
2226
import org.springframework.beans.factory.annotation.Qualifier;
2327
import org.springframework.core.MethodParameter;
@@ -40,6 +44,13 @@
4044
*/
4145
public class SortHandlerMethodArgumentResolverUnitTests extends SortDefaultUnitTests {
4246

47+
static MethodParameter PARAMETER;
48+
49+
@BeforeClass
50+
public static void setUp() throws Exception {
51+
PARAMETER = new MethodParameter(Controller.class.getMethod("supportedMethod", Sort.class), 0);
52+
}
53+
4354
/**
4455
* @see DATACMNS-351
4556
*/
@@ -126,6 +137,61 @@ public void requestForMultipleSortPropertiesIsUnmarshalledCorrectly() throws Exc
126137
assertThat(result, is(new Sort(Direction.ASC, "firstname", "lastname")));
127138
}
128139

140+
/**
141+
* @see DATACMNS-408
142+
*/
143+
@Test
144+
public void parsesEmptySortToNull() throws Exception {
145+
146+
MockHttpServletRequest request = new MockHttpServletRequest();
147+
request.addParameter("sort", "");
148+
149+
assertThat(resolveSort(request, PARAMETER), is(nullValue()));
150+
}
151+
152+
/**
153+
* @see DATACMNS-408
154+
*/
155+
@Test
156+
public void sortParamIsInvalidProperty() throws Exception {
157+
158+
MockHttpServletRequest request = new MockHttpServletRequest();
159+
request.addParameter("sort", ",DESC");
160+
161+
assertThat(resolveSort(request, PARAMETER), is(nullValue()));
162+
}
163+
164+
/**
165+
* @see DATACMNS-408
166+
*/
167+
@Test
168+
public void sortParamIsInvalidPropertyWhenMultiProperty() throws Exception {
169+
170+
MockHttpServletRequest request = new MockHttpServletRequest();
171+
request.addParameter("sort", "property1,,DESC");
172+
173+
assertThat(resolveSort(request, PARAMETER), is(new Sort(DESC, "property1")));
174+
}
175+
176+
/**
177+
* @see DATACMNS-408
178+
*/
179+
@Test
180+
public void sortParamIsEmptyWhenMultiParams() throws Exception {
181+
182+
MockHttpServletRequest request = new MockHttpServletRequest();
183+
request.addParameter("sort", "property,DESC");
184+
request.addParameter("sort", "");
185+
186+
assertThat(resolveSort(request, PARAMETER), is(new Sort(DESC, "property")));
187+
}
188+
189+
private static Sort resolveSort(HttpServletRequest request, MethodParameter parameter) throws Exception {
190+
191+
SortHandlerMethodArgumentResolver resolver = new SortHandlerMethodArgumentResolver();
192+
return resolver.resolveArgument(parameter, null, new ServletWebRequest(request), null);
193+
}
194+
129195
private static void assertSupportedAndResolvedTo(NativeWebRequest request, MethodParameter parameter, Sort sort) {
130196

131197
SortHandlerMethodArgumentResolver resolver = new SortHandlerMethodArgumentResolver();

0 commit comments

Comments
 (0)