Skip to content

Commit b6449ba

Browse files
committed
List all unsatisfied request param groups
Issue: SPR-12854
1 parent 0b8554f commit b6449ba

File tree

3 files changed

+79
-21
lines changed

3 files changed

+79
-21
lines changed

spring-web/src/main/java/org/springframework/web/bind/UnsatisfiedServletRequestParameterException.java

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
1616

1717
package org.springframework.web.bind;
1818

19+
import java.util.Arrays;
1920
import java.util.Iterator;
21+
import java.util.List;
2022
import java.util.Map;
2123

24+
import org.springframework.util.Assert;
25+
import org.springframework.util.CollectionUtils;
2226
import org.springframework.util.ObjectUtils;
2327
import org.springframework.util.StringUtils;
2428

@@ -34,7 +38,7 @@
3438
@SuppressWarnings("serial")
3539
public class UnsatisfiedServletRequestParameterException extends ServletRequestBindingException {
3640

37-
private final String[] paramConditions;
41+
private final List<String[]> paramConditions;
3842

3943
private final Map<String, String[]> actualParams;
4044

@@ -46,15 +50,42 @@ public class UnsatisfiedServletRequestParameterException extends ServletRequestB
4650
*/
4751
public UnsatisfiedServletRequestParameterException(String[] paramConditions, Map<String, String[]> actualParams) {
4852
super("");
53+
this.paramConditions = Arrays.<String[]>asList(paramConditions);
54+
this.actualParams = actualParams;
55+
}
56+
57+
/**
58+
* Create a new UnsatisfiedServletRequestParameterException.
59+
* @param paramConditions all sets of parameter conditions that have been violated
60+
* @param actualParams the actual parameter Map associated with the ServletRequest
61+
* @since 4.2
62+
*/
63+
public UnsatisfiedServletRequestParameterException(List<String[]> paramConditions,
64+
Map<String, String[]> actualParams) {
65+
66+
super("");
67+
Assert.isTrue(!CollectionUtils.isEmpty(paramConditions));
4968
this.paramConditions = paramConditions;
5069
this.actualParams = actualParams;
5170
}
5271

5372

5473
@Override
5574
public String getMessage() {
56-
return "Parameter conditions \"" + StringUtils.arrayToDelimitedString(this.paramConditions, ", ") +
57-
"\" not met for actual request parameters: " + requestParameterMapToString(this.actualParams);
75+
StringBuilder sb = new StringBuilder("Parameter conditions ");
76+
int i = 0;
77+
for (String[] conditions : this.paramConditions) {
78+
if (i > 0) {
79+
sb.append(" OR ");
80+
}
81+
sb.append("\"");
82+
sb.append(StringUtils.arrayToDelimitedString(conditions, ", "));
83+
sb.append("\"");
84+
i++;
85+
}
86+
sb.append(" not met for actual request parameters: ");
87+
sb.append(requestParameterMapToString(this.actualParams));
88+
return sb.toString();
5889
}
5990

6091
private static String requestParameterMapToString(Map<String, String[]> actualParams) {
@@ -70,10 +101,20 @@ private static String requestParameterMapToString(Map<String, String[]> actualPa
70101
}
71102

72103
/**
73-
* Return the parameter conditions that have been violated.
104+
* Return the parameter conditions that have been violated or the first group
105+
* in case of multiple groups.
74106
* @see org.springframework.web.bind.annotation.RequestMapping#params()
75107
*/
76108
public final String[] getParamConditions() {
109+
return this.paramConditions.get(0);
110+
}
111+
112+
/**
113+
* Return all parameter condition groups that have been violated.
114+
* @see org.springframework.web.bind.annotation.RequestMapping#params()
115+
* @since 4.2
116+
*/
117+
public final List<String[]> getParamConditionGroups() {
77118
return this.paramConditions;
78119
}
79120

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
2222
import java.util.HashSet;
2323
import java.util.LinkedHashMap;
2424
import java.util.LinkedHashSet;
25+
import java.util.List;
2526
import java.util.Map;
2627
import java.util.Map.Entry;
2728
import java.util.Set;
@@ -205,7 +206,7 @@ else if (patternAndMethodMatches.isEmpty() && !allowedMethods.isEmpty()) {
205206

206207
Set<MediaType> consumableMediaTypes;
207208
Set<MediaType> producibleMediaTypes;
208-
Set<String> paramConditions;
209+
List<String[]> paramConditions;
209210

210211
if (patternAndMethodMatches.isEmpty()) {
211212
consumableMediaTypes = getConsumableMediaTypes(request, patternMatches);
@@ -234,8 +235,7 @@ else if (!producibleMediaTypes.isEmpty()) {
234235
throw new HttpMediaTypeNotAcceptableException(new ArrayList<MediaType>(producibleMediaTypes));
235236
}
236237
else if (!CollectionUtils.isEmpty(paramConditions)) {
237-
String[] params = paramConditions.toArray(new String[paramConditions.size()]);
238-
throw new UnsatisfiedServletRequestParameterException(params, request.getParameterMap());
238+
throw new UnsatisfiedServletRequestParameterException(paramConditions, request.getParameterMap());
239239
}
240240
else {
241241
return null;
@@ -262,18 +262,21 @@ private Set<MediaType> getProducibleMediaTypes(HttpServletRequest request, Set<R
262262
return result;
263263
}
264264

265-
private Set<String> getRequestParams(HttpServletRequest request, Set<RequestMappingInfo> partialMatches) {
265+
private List<String[]> getRequestParams(HttpServletRequest request, Set<RequestMappingInfo> partialMatches) {
266+
List<String[]> result = new ArrayList<String[]>();
266267
for (RequestMappingInfo partialMatch : partialMatches) {
267268
ParamsRequestCondition condition = partialMatch.getParamsCondition();
268-
if (!CollectionUtils.isEmpty(condition.getExpressions()) && (condition.getMatchingCondition(request) == null)) {
269-
Set<String> expressions = new HashSet<String>();
270-
for (NameValueExpression<String> expr : condition.getExpressions()) {
271-
expressions.add(expr.toString());
269+
Set<NameValueExpression<String>> expressions = condition.getExpressions();
270+
if (!CollectionUtils.isEmpty(expressions) && condition.getMatchingCondition(request) == null) {
271+
int i = 0;
272+
String[] array = new String[expressions.size()];
273+
for (NameValueExpression<String> expression : expressions) {
274+
array[i++] = expression.toString();
272275
}
273-
return expressions;
276+
result.add(array);
274277
}
275278
}
276-
return null;
279+
return result;
277280
}
278281

279282
}

spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,12 +16,17 @@
1616

1717
package org.springframework.web.servlet.mvc.method;
1818

19+
import static org.hamcrest.Matchers.*;
20+
import static org.junit.Assert.*;
21+
1922
import java.lang.reflect.Method;
2023
import java.util.Arrays;
2124
import java.util.Collections;
2225
import java.util.HashSet;
26+
import java.util.List;
2327
import java.util.Map;
2428
import java.util.Set;
29+
2530
import javax.servlet.http.HttpServletRequest;
2631

2732
import org.junit.Before;
@@ -54,8 +59,6 @@
5459
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
5560
import org.springframework.web.util.UrlPathHelper;
5661

57-
import static org.junit.Assert.*;
58-
5962
/**
6063
* Test fixture with {@link RequestMappingInfoHandlerMapping}.
6164
*
@@ -211,6 +214,8 @@ private void testMediaTypeNotAccepted(String url) throws Exception {
211214
}
212215
}
213216

217+
// SPR-12854
218+
214219
@Test
215220
public void testUnsatisfiedServletRequestParameterException() throws Exception {
216221
try {
@@ -219,8 +224,10 @@ public void testUnsatisfiedServletRequestParameterException() throws Exception {
219224
fail("UnsatisfiedServletRequestParameterException expected");
220225
}
221226
catch (UnsatisfiedServletRequestParameterException ex) {
222-
assertArrayEquals("Invalid request parameter conditions",
223-
new String[] { "foo=bar" }, ex.getParamConditions());
227+
List<String[]> groups = ex.getParamConditionGroups();
228+
assertEquals(2, groups.size());
229+
assertThat(Arrays.asList("foo=bar", "bar=baz"),
230+
containsInAnyOrder(groups.get(0)[0], groups.get(1)[0]));
224231
}
225232
}
226233

@@ -408,6 +415,7 @@ private Map<String, String> getUriTemplateVariables(HttpServletRequest request)
408415
}
409416

410417

418+
@SuppressWarnings("unused")
411419
@Controller
412420
private static class TestController {
413421

@@ -441,6 +449,11 @@ public String param() {
441449
return "";
442450
}
443451

452+
@RequestMapping(value = "/params", params="bar=baz")
453+
public String param2() {
454+
return "";
455+
}
456+
444457
@RequestMapping(value = "/content", produces="application/xml")
445458
public String xmlContent() {
446459
return "";
@@ -452,6 +465,7 @@ public String nonXmlContent() {
452465
}
453466
}
454467

468+
@SuppressWarnings("unused")
455469
@Controller
456470
private static class UserController {
457471

0 commit comments

Comments
 (0)