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
This commit is contained in:
parent
399f887128
commit
d3eda09c01
|
|
@ -74,6 +74,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
|
||||||
this.expressionContext = (beanFactory != null) ? new BeanExpressionContext(beanFactory, new RequestScope()) : null;
|
this.expressionContext = (beanFactory != null) ? new BeanExpressionContext(beanFactory, new RequestScope()) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final Object resolveArgument(
|
public final Object resolveArgument(
|
||||||
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||||
|
|
@ -96,11 +97,17 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
|
||||||
arg = resolveDefaultValue(namedValueInfo.defaultValue);
|
arg = resolveDefaultValue(namedValueInfo.defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean emptyArgValue = "".equals(arg);
|
||||||
|
|
||||||
if (binderFactory != null) {
|
if (binderFactory != null) {
|
||||||
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
|
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
|
||||||
arg = binder.convertIfNecessary(arg, paramType, parameter);
|
arg = binder.convertIfNecessary(arg, paramType, parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (emptyArgValue && (arg == null)) {
|
||||||
|
handleMissingValue(namedValueInfo.name, parameter);
|
||||||
|
}
|
||||||
|
|
||||||
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
|
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
|
||||||
|
|
||||||
return arg;
|
return arg;
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.web.method.annotation;
|
package org.springframework.web.method.annotation;
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -32,6 +25,7 @@ import javax.servlet.http.Part;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
|
||||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.ParameterNameDiscoverer;
|
import org.springframework.core.ParameterNameDiscoverer;
|
||||||
|
|
@ -41,13 +35,20 @@ import org.springframework.mock.web.test.MockMultipartFile;
|
||||||
import org.springframework.mock.web.test.MockMultipartHttpServletRequest;
|
import org.springframework.mock.web.test.MockMultipartHttpServletRequest;
|
||||||
import org.springframework.mock.web.test.MockPart;
|
import org.springframework.mock.web.test.MockPart;
|
||||||
import org.springframework.web.bind.MissingServletRequestParameterException;
|
import org.springframework.web.bind.MissingServletRequestParameterException;
|
||||||
|
import org.springframework.web.bind.WebDataBinder;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RequestPart;
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
|
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||||
|
import org.springframework.web.bind.support.WebRequestDataBinder;
|
||||||
import org.springframework.web.context.request.NativeWebRequest;
|
import org.springframework.web.context.request.NativeWebRequest;
|
||||||
import org.springframework.web.context.request.ServletWebRequest;
|
import org.springframework.web.context.request.ServletWebRequest;
|
||||||
import org.springframework.web.multipart.MultipartException;
|
import org.springframework.web.multipart.MultipartException;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.BDDMockito.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test fixture with {@link org.springframework.web.method.annotation.RequestParamMethodArgumentResolver}.
|
* Test fixture with {@link org.springframework.web.method.annotation.RequestParamMethodArgumentResolver}.
|
||||||
*
|
*
|
||||||
|
|
@ -242,6 +243,23 @@ public class RequestParamMethodArgumentResolverTests {
|
||||||
fail("Expected exception");
|
fail("Expected exception");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SPR-10402
|
||||||
|
|
||||||
|
@Test(expected = MissingServletRequestParameterException.class)
|
||||||
|
public void missingRequestParamEmptyValueConvertedToNull() throws Exception {
|
||||||
|
|
||||||
|
WebDataBinder binder = new WebRequestDataBinder(null);
|
||||||
|
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
|
||||||
|
|
||||||
|
WebDataBinderFactory binderFactory = mock(WebDataBinderFactory.class);
|
||||||
|
given(binderFactory.createBinder(webRequest, null, "stringNotAnnot")).willReturn(binder);
|
||||||
|
|
||||||
|
this.request.addParameter("stringNotAnnot", "");
|
||||||
|
|
||||||
|
resolver.resolveArgument(paramStringNotAnnot, null, webRequest, binderFactory);
|
||||||
|
fail("Expected exception");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveSimpleTypeParam() throws Exception {
|
public void resolveSimpleTypeParam() throws Exception {
|
||||||
request.setParameter("stringNotAnnot", "plainValue");
|
request.setParameter("stringNotAnnot", "plainValue");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue