Skip to content

Commit d3eda09

Browse files
committed
Allow treating empty @RequestParam as missing value
If type conversion turns an empty request parameter value (i.e. "") to null, we should treat it as a missing value. By default the ConversionService doesn't change empty strings and therefore one must explicitly convert them to null for example by registering a StringTrimmerEditor with emptyAsNull=true. Issue: SPR-10402
1 parent 399f887 commit d3eda09

File tree

2 files changed

+32
-7
lines changed

2 files changed

+32
-7
lines changed

spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public AbstractNamedValueMethodArgumentResolver(ConfigurableBeanFactory beanFact
7474
this.expressionContext = (beanFactory != null) ? new BeanExpressionContext(beanFactory, new RequestScope()) : null;
7575
}
7676

77+
@Override
7778
public final Object resolveArgument(
7879
MethodParameter parameter, ModelAndViewContainer mavContainer,
7980
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
@@ -96,11 +97,17 @@ else if ("".equals(arg) && (namedValueInfo.defaultValue != null)) {
9697
arg = resolveDefaultValue(namedValueInfo.defaultValue);
9798
}
9899

100+
boolean emptyArgValue = "".equals(arg);
101+
99102
if (binderFactory != null) {
100103
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
101104
arg = binder.convertIfNecessary(arg, paramType, parameter);
102105
}
103106

107+
if (emptyArgValue && (arg == null)) {
108+
handleMissingValue(namedValueInfo.name, parameter);
109+
}
110+
104111
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
105112

106113
return arg;

spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolverTests.java

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@
1616

1717
package org.springframework.web.method.annotation;
1818

19-
import static org.junit.Assert.assertArrayEquals;
20-
import static org.junit.Assert.assertEquals;
21-
import static org.junit.Assert.assertFalse;
22-
import static org.junit.Assert.assertNull;
23-
import static org.junit.Assert.assertTrue;
24-
import static org.junit.Assert.fail;
25-
2619
import java.lang.reflect.Method;
2720
import java.util.Arrays;
2821
import java.util.List;
@@ -32,6 +25,7 @@
3225

3326
import org.junit.Before;
3427
import org.junit.Test;
28+
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
3529
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
3630
import org.springframework.core.MethodParameter;
3731
import org.springframework.core.ParameterNameDiscoverer;
@@ -41,13 +35,20 @@
4135
import org.springframework.mock.web.test.MockMultipartHttpServletRequest;
4236
import org.springframework.mock.web.test.MockPart;
4337
import org.springframework.web.bind.MissingServletRequestParameterException;
38+
import org.springframework.web.bind.WebDataBinder;
4439
import org.springframework.web.bind.annotation.RequestParam;
4540
import org.springframework.web.bind.annotation.RequestPart;
41+
import org.springframework.web.bind.support.WebDataBinderFactory;
42+
import org.springframework.web.bind.support.WebRequestDataBinder;
4643
import org.springframework.web.context.request.NativeWebRequest;
4744
import org.springframework.web.context.request.ServletWebRequest;
4845
import org.springframework.web.multipart.MultipartException;
4946
import org.springframework.web.multipart.MultipartFile;
5047

48+
import static org.junit.Assert.*;
49+
import static org.mockito.BDDMockito.*;
50+
import static org.mockito.Mockito.*;
51+
5152
/**
5253
* Test fixture with {@link org.springframework.web.method.annotation.RequestParamMethodArgumentResolver}.
5354
*
@@ -242,6 +243,23 @@ public void missingRequestParam() throws Exception {
242243
fail("Expected exception");
243244
}
244245

246+
// SPR-10402
247+
248+
@Test(expected = MissingServletRequestParameterException.class)
249+
public void missingRequestParamEmptyValueConvertedToNull() throws Exception {
250+
251+
WebDataBinder binder = new WebRequestDataBinder(null);
252+
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
253+
254+
WebDataBinderFactory binderFactory = mock(WebDataBinderFactory.class);
255+
given(binderFactory.createBinder(webRequest, null, "stringNotAnnot")).willReturn(binder);
256+
257+
this.request.addParameter("stringNotAnnot", "");
258+
259+
resolver.resolveArgument(paramStringNotAnnot, null, webRequest, binderFactory);
260+
fail("Expected exception");
261+
}
262+
245263
@Test
246264
public void resolveSimpleTypeParam() throws Exception {
247265
request.setParameter("stringNotAnnot", "plainValue");

0 commit comments

Comments
 (0)