Consistent java.util.Optional resolution, lenient handling of optional multipart files, correct Servlet 3.0 Part list/array selection

Issue: SPR-13418
Issue: SPR-13849
Issue: SPR-13850
Issue: SPR-13893
This commit is contained in:
Juergen Hoeller
2016-01-26 18:06:15 +01:00
parent a3a5a03ee3
commit b4f33adf48
23 changed files with 820 additions and 451 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,12 +48,13 @@ public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMeth
super(null);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
if (!parameter.hasParameterAnnotation(MatrixVariable.class)) {
return false;
}
if (Map.class.isAssignableFrom(parameter.getParameterType())) {
if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
String variableName = parameter.getParameterAnnotation(MatrixVariable.class).name();
return StringUtils.hasText(variableName);
}
@@ -67,13 +68,10 @@ public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMeth
}
@Override
@SuppressWarnings("unchecked")
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
@SuppressWarnings("unchecked")
Map<String, MultiValueMap<String, String>> pathParameters =
(Map<String, MultiValueMap<String, String>>) request.getAttribute(
HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
Map<String, MultiValueMap<String, String>> pathParameters = (Map<String, MultiValueMap<String, String>>)
request.getAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
if (CollectionUtils.isEmpty(pathParameters)) {
return null;
}
@@ -92,10 +90,10 @@ public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMeth
for (MultiValueMap<String, String> params : pathParameters.values()) {
if (params.containsKey(name)) {
if (found) {
String paramType = parameter.getParameterType().getName();
String paramType = parameter.getNestedParameterType().getName();
throw new ServletRequestBindingException(
"Found more than one match for URI path parameter '" + name +
"' for parameter type [" + paramType + "]. Use pathVar attribute to disambiguate.");
"' for parameter type [" + paramType + "]. Use 'pathVar' attribute to disambiguate.");
}
paramValues.addAll(params.get(name));
found = true;
@@ -117,7 +115,7 @@ public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMeth
@Override
protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException {
throw new ServletRequestBindingException("Missing matrix variable '" + name +
"' for method parameter of type " + parameter.getParameterType().getSimpleName());
"' for method parameter of type " + parameter.getNestedParameterType().getSimpleName());
}
@@ -127,4 +125,5 @@ public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMeth
super(annotation.name(), annotation.required(), annotation.defaultValue());
}
}
}
}

View File

@@ -79,7 +79,7 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod
if (!parameter.hasParameterAnnotation(PathVariable.class)) {
return false;
}
if (Map.class.isAssignableFrom(parameter.getParameterType())) {
if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
String paramName = parameter.getParameterAnnotation(PathVariable.class).value();
return StringUtils.hasText(paramName);
}
@@ -95,10 +95,9 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod
@Override
@SuppressWarnings("unchecked")
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
Map<String, String> uriTemplateVars =
(Map<String, String>) request.getAttribute(
HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
return (uriTemplateVars != null) ? uriTemplateVars.get(name) : null;
Map<String, String> uriTemplateVars = (Map<String, String>) request.getAttribute(
HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
return (uriTemplateVars != null ? uriTemplateVars.get(name) : null);
}
@Override
@@ -127,7 +126,7 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod
public void contributeMethodArgument(MethodParameter parameter, Object value,
UriComponentsBuilder builder, Map<String, Object> uriVariables, ConversionService conversionService) {
if (Map.class.isAssignableFrom(parameter.getParameterType())) {
if (Map.class.isAssignableFrom(parameter.getNestedParameterType())) {
return;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,20 +16,15 @@
package org.springframework.web.servlet.mvc.method.annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.UsesJava8;
import org.springframework.util.Assert;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.WebDataBinder;
@@ -41,12 +36,10 @@ import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.multipart.support.MultipartResolutionDelegate;
import org.springframework.web.multipart.support.RequestPartServletServerHttpRequest;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
import org.springframework.web.util.WebUtils;
/**
* Resolves the following method arguments:
@@ -65,12 +58,13 @@ import org.springframework.web.util.WebUtils;
* it is derived from the name of the method argument.
*
* <p>Automatic validation may be applied if the argument is annotated with
* {@code @javax.validation.Valid}. In case of validation failure, a
* {@link MethodArgumentNotValidException} is raised and a 400 response status
* code returned if {@link DefaultHandlerExceptionResolver} is configured.
* {@code @javax.validation.Valid}. In case of validation failure, a {@link MethodArgumentNotValidException}
* is raised and a 400 response status code returned if
* {@link org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver} is configured.
*
* @author Rossen Stoyanchev
* @author Brian Clozel
* @author Juergen Hoeller
* @since 3.1
*/
public class RequestPartMethodArgumentResolver extends AbstractMessageConverterMethodArgumentResolver {
@@ -107,18 +101,10 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM
return true;
}
else {
if (parameter.hasParameterAnnotation(RequestParam.class)){
return false;
}
else if (MultipartFile.class == parameter.getParameterType()) {
return true;
}
else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) {
return true;
}
else {
if (parameter.hasParameterAnnotation(RequestParam.class)) {
return false;
}
return MultipartResolutionDelegate.isMultipartArgument(parameter.nestedIfOptional());
}
}
@@ -128,87 +114,58 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM
NativeWebRequest request, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
assertIsMultipartRequest(servletRequest);
RequestPart requestPart = parameter.getParameterAnnotation(RequestPart.class);
boolean isRequired = ((requestPart == null || requestPart.required()) && !parameter.isOptional());
MultipartHttpServletRequest multipartRequest =
WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);
String name = getPartName(parameter, requestPart);
parameter = parameter.nestedIfOptional();
Object arg = null;
Class<?> paramType = parameter.getParameterType();
boolean optional = paramType.getName().equals("java.util.Optional");
if (optional) {
parameter.increaseNestingLevel();
paramType = parameter.getNestedParameterType();
}
String partName = getPartName(parameter);
Object arg;
if (MultipartFile.class == paramType) {
Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
arg = multipartRequest.getFile(partName);
}
else if (isMultipartFileCollection(parameter)) {
Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
arg = multipartRequest.getFiles(partName);
}
else if (isMultipartFileArray(parameter)) {
Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
List<MultipartFile> files = multipartRequest.getFiles(partName);
arg = files.toArray(new MultipartFile[files.size()]);
}
else if ("javax.servlet.http.Part".equals(paramType.getName())) {
assertIsMultipartRequest(servletRequest);
arg = servletRequest.getPart(partName);
}
else if (isPartCollection(parameter)) {
assertIsMultipartRequest(servletRequest);
arg = new ArrayList<Object>(servletRequest.getParts());
}
else if (isPartArray(parameter)) {
assertIsMultipartRequest(servletRequest);
arg = RequestPartResolver.resolvePart(servletRequest);
Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);
if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {
arg = mpArg;
}
else {
try {
HttpInputMessage inputMessage = new RequestPartServletServerHttpRequest(servletRequest, partName);
HttpInputMessage inputMessage = new RequestPartServletServerHttpRequest(servletRequest, name);
arg = readWithMessageConverters(inputMessage, parameter, parameter.getNestedGenericParameterType());
WebDataBinder binder = binderFactory.createBinder(request, arg, partName);
WebDataBinder binder = binderFactory.createBinder(request, arg, name);
if (arg != null) {
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + partName, binder.getBindingResult());
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
}
catch (MissingServletRequestPartException ex) {
// handled below
arg = null;
if (isRequired) {
throw ex;
}
}
catch (MultipartException ex) {
if (isRequired) {
throw ex;
}
}
}
RequestPart requestPart = parameter.getParameterAnnotation(RequestPart.class);
boolean isRequired = ((requestPart == null || requestPart.required()) && !optional);
if (arg == null && isRequired) {
throw new MissingServletRequestPartException(partName);
if (!MultipartResolutionDelegate.isMultipartRequest(servletRequest)) {
throw new MultipartException("Current request is not a multipart request");
}
else {
throw new MissingServletRequestPartException(name);
}
}
if (optional) {
arg = Optional.ofNullable(arg);
if (parameter.isOptional()) {
arg = OptionalResolver.resolveValue(arg);
}
return arg;
}
private static void assertIsMultipartRequest(HttpServletRequest request) {
String contentType = request.getContentType();
if (contentType == null || !contentType.toLowerCase().startsWith("multipart/")) {
throw new MultipartException("The current request is not a multipart request");
}
}
private String getPartName(MethodParameter methodParam) {
RequestPart requestPart = methodParam.getParameterAnnotation(RequestPart.class);
private String getPartName(MethodParameter methodParam, RequestPart requestPart) {
String partName = (requestPart != null ? requestPart.name() : "");
if (partName.length() == 0) {
partName = methodParam.getParameterName();
@@ -221,46 +178,18 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM
return partName;
}
private boolean isMultipartFileCollection(MethodParameter methodParam) {
Class<?> collectionType = getCollectionParameterType(methodParam);
return MultipartFile.class == collectionType;
}
private boolean isMultipartFileArray(MethodParameter methodParam) {
Class<?> paramType = methodParam.getNestedParameterType().getComponentType();
return MultipartFile.class == paramType;
}
private boolean isPartCollection(MethodParameter methodParam) {
Class<?> collectionType = getCollectionParameterType(methodParam);
return (collectionType != null && "javax.servlet.http.Part".equals(collectionType.getName()));
}
private boolean isPartArray(MethodParameter methodParam) {
Class<?> paramType = methodParam.getNestedParameterType().getComponentType();
return (paramType != null && "javax.servlet.http.Part".equals(paramType.getName()));
}
private Class<?> getCollectionParameterType(MethodParameter methodParam) {
Class<?> paramType = methodParam.getNestedParameterType();
if (Collection.class == paramType || List.class.isAssignableFrom(paramType)){
Class<?> valueType = GenericCollectionTypeResolver.getCollectionParameterType(methodParam);
if (valueType != null) {
return valueType;
}
}
return null;
}
/**
* Inner class to avoid hard-coded dependency on Servlet 3.0 Part type...
* Inner class to avoid hard-coded dependency on Java 8 Optional type...
*/
private static class RequestPartResolver {
private static class OptionalResolver {
public static Object resolvePart(HttpServletRequest servletRequest) throws Exception {
Collection<Part> parts = servletRequest.getParts();
return parts.toArray(new Part[parts.size()]);
public static Object resolveValue(Object value) {
if (value == null || (value instanceof Collection && ((Collection) value).isEmpty()) ||
(value instanceof Object[] && ((Object[]) value).length == 0)) {
return Optional.empty();
}
return Optional.of(value);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,7 +52,7 @@ public class ServletCookieValueMethodArgumentResolver extends AbstractCookieValu
protected Object resolveName(String cookieName, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
Cookie cookieValue = WebUtils.getCookie(servletRequest, cookieName);
if (Cookie.class.isAssignableFrom(parameter.getParameterType())) {
if (Cookie.class.isAssignableFrom(parameter.getNestedParameterType())) {
return cookieValue;
}
else if (cookieValue != null) {

View File

@@ -262,6 +262,12 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
this.returnType = ResolvableType.forType(super.getGenericParameterType()).getGeneric(0);
}
public ConcurrentResultMethodParameter(ConcurrentResultMethodParameter original) {
super(original);
this.returnValue = original.returnValue;
this.returnType = original.returnType;
}
@Override
public Class<?> getParameterType() {
if (this.returnValue != null) {
@@ -283,6 +289,11 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
public Type getGenericParameterType() {
return this.returnType.getType();
}
@Override
public ConcurrentResultMethodParameter clone() {
return new ConcurrentResultMethodParameter(this);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,6 +41,7 @@ import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.mock.web.test.MockMultipartFile;
import org.springframework.mock.web.test.MockMultipartHttpServletRequest;
import org.springframework.mock.web.test.MockPart;
import org.springframework.util.ReflectionUtils;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.WebDataBinder;
@@ -53,7 +54,6 @@ import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.multipart.support.RequestPartServletServerHttpRequest;
import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*;
@@ -86,7 +86,9 @@ public class RequestPartMethodArgumentResolverTests {
private MethodParameter paramPartArray;
private MethodParameter paramRequestParamAnnot;
private MethodParameter optionalMultipartFile;
private MethodParameter optionalMultipartFileList;
private MethodParameter optionalPart;
private MethodParameter optionalPartList;
private MethodParameter optionalRequestPart;
private NativeWebRequest webRequest;
@@ -97,10 +99,7 @@ public class RequestPartMethodArgumentResolverTests {
@SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception {
Method method = getClass().getMethod("handle", SimpleBean.class, SimpleBean.class,
SimpleBean.class, MultipartFile.class, List.class, MultipartFile[].class,
Integer.TYPE, MultipartFile.class, Part.class, List.class, Part[].class,
MultipartFile.class, Optional.class, Optional.class, Optional.class);
Method method = ReflectionUtils.findMethod(getClass(), "handle", (Class<?>[]) null);
paramRequestPart = new SynthesizingMethodParameter(method, 0);
paramRequestPart.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
@@ -119,9 +118,13 @@ public class RequestPartMethodArgumentResolverTests {
paramRequestParamAnnot = new SynthesizingMethodParameter(method, 11);
optionalMultipartFile = new SynthesizingMethodParameter(method, 12);
optionalMultipartFile.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
optionalPart = new SynthesizingMethodParameter(method, 13);
optionalMultipartFileList = new SynthesizingMethodParameter(method, 13);
optionalMultipartFileList.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
optionalPart = new SynthesizingMethodParameter(method, 14);
optionalPart.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
optionalRequestPart = new SynthesizingMethodParameter(method, 14);
optionalPartList = new SynthesizingMethodParameter(method, 15);
optionalPartList.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
optionalRequestPart = new SynthesizingMethodParameter(method, 16);
messageConverter = mock(HttpMessageConverter.class);
given(messageConverter.getSupportedMediaTypes()).willReturn(Collections.singletonList(MediaType.TEXT_PLAIN));
@@ -136,35 +139,41 @@ public class RequestPartMethodArgumentResolverTests {
multipartRequest = new MockMultipartHttpServletRequest();
multipartRequest.addFile(multipartFile1);
multipartRequest.addFile(multipartFile2);
multipartRequest.addFile(new MockMultipartFile("otherPart", "", "text/plain", content));
webRequest = new ServletWebRequest(multipartRequest, new MockHttpServletResponse());
}
@Test
public void supportsParameter() {
assertTrue("RequestPart parameter not supported", resolver.supportsParameter(paramRequestPart));
assertTrue("MultipartFile parameter not supported", resolver.supportsParameter(paramMultipartFileNotAnnot));
assertTrue("Part parameter not supported", resolver.supportsParameter(paramPart));
assertTrue("List<Part> parameter not supported", resolver.supportsParameter(paramPartList));
assertTrue("Part[] parameter not supported", resolver.supportsParameter(paramPartArray));
assertTrue("MultipartFile parameter not supported", resolver.supportsParameter(paramMultipartFile));
assertTrue("List<MultipartFile> parameter not supported", resolver.supportsParameter(paramMultipartFileList));
assertTrue("MultipartFile[] parameter not supported", resolver.supportsParameter(paramMultipartFileArray));
assertFalse("non-RequestPart parameter should not be supported", resolver.supportsParameter(paramInt));
assertFalse("@RequestParam args should not be supported", resolver.supportsParameter(paramRequestParamAnnot));
assertTrue(resolver.supportsParameter(paramRequestPart));
assertTrue(resolver.supportsParameter(paramNamedRequestPart));
assertTrue(resolver.supportsParameter(paramValidRequestPart));
assertTrue(resolver.supportsParameter(paramMultipartFile));
assertTrue(resolver.supportsParameter(paramMultipartFileList));
assertTrue(resolver.supportsParameter(paramMultipartFileArray));
assertFalse(resolver.supportsParameter(paramInt));
assertTrue(resolver.supportsParameter(paramMultipartFileNotAnnot));
assertTrue(resolver.supportsParameter(paramPart));
assertTrue(resolver.supportsParameter(paramPartList));
assertTrue(resolver.supportsParameter(paramPartArray));
assertFalse(resolver.supportsParameter(paramRequestParamAnnot));
assertTrue(resolver.supportsParameter(optionalMultipartFile));
assertTrue(resolver.supportsParameter(optionalMultipartFileList));
assertTrue(resolver.supportsParameter(optionalPart));
assertTrue(resolver.supportsParameter(optionalPartList));
assertTrue(resolver.supportsParameter(optionalRequestPart));
}
@Test
public void resolveMultipartFile() throws Exception {
Object actual = resolver.resolveArgument(paramMultipartFile, null, webRequest, null);
assertNotNull(actual);
assertSame(multipartFile1, actual);
}
@Test
public void resolveMultipartFileList() throws Exception {
Object actual = resolver.resolveArgument(paramMultipartFileList, null, webRequest, null);
assertNotNull(actual);
assertTrue(actual instanceof List);
assertEquals(Arrays.asList(multipartFile1, multipartFile2), actual);
}
@@ -175,6 +184,7 @@ public class RequestPartMethodArgumentResolverTests {
assertNotNull(actual);
assertTrue(actual instanceof MultipartFile[]);
MultipartFile[] parts = (MultipartFile[]) actual;
assertEquals(2, parts.length);
assertEquals(parts[0], multipartFile1);
assertEquals(parts[1], multipartFile2);
}
@@ -184,6 +194,7 @@ public class RequestPartMethodArgumentResolverTests {
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
MultipartFile expected = new MockMultipartFile("multipartFileNotAnnot", "Hello World".getBytes());
request.addFile(expected);
request.addFile(new MockMultipartFile("otherPart", "", "text/plain", "Hello World".getBytes()));
webRequest = new ServletWebRequest(request);
Object result = resolver.resolveArgument(paramMultipartFileNotAnnot, null, webRequest, null);
@@ -194,52 +205,52 @@ public class RequestPartMethodArgumentResolverTests {
@Test
public void resolvePartArgument() throws Exception {
MockPart expected = new MockPart("part", "Hello World".getBytes());
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContentType("multipart/form-data");
MockPart expected = new MockPart("part", "Hello World".getBytes());
request.addPart(expected);
request.addPart(new MockPart("otherPart", "Hello World".getBytes()));
webRequest = new ServletWebRequest(request);
Object result = resolver.resolveArgument(paramPart, null, webRequest, null);
assertTrue(result instanceof Part);
assertEquals("Invalid result", expected, result);
}
@Test
public void resolvePartListArgument() throws Exception {
MockPart part1 = new MockPart("requestPart1", "Hello World 1".getBytes());
MockPart part2 = new MockPart("requestPart2", "Hello World 2".getBytes());
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContentType("multipart/form-data");
MockPart part1 = new MockPart("requestPart", "Hello World 1".getBytes());
MockPart part2 = new MockPart("requestPart", "Hello World 2".getBytes());
request.addPart(part1);
request.addPart(part2);
request.addPart(new MockPart("otherPart", "Hello World".getBytes()));
webRequest = new ServletWebRequest(request);
Object result = resolver.resolveArgument(paramPartList, null, webRequest, null);
assertTrue(result instanceof List);
assertEquals(Arrays.asList(part1, part2), result);
}
@Test
public void resolvePartArrayArgument() throws Exception {
MockPart part1 = new MockPart("requestPart1", "Hello World 1".getBytes());
MockPart part2 = new MockPart("requestPart2", "Hello World 2".getBytes());
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContentType("multipart/form-data");
MockPart part1 = new MockPart("requestPart", "Hello World 1".getBytes());
MockPart part2 = new MockPart("requestPart", "Hello World 2".getBytes());
request.addPart(part1);
request.addPart(part2);
request.addPart(new MockPart("otherPart", "Hello World".getBytes()));
webRequest = new ServletWebRequest(request);
Object result = resolver.resolveArgument(paramPartArray, null, webRequest, null);
assertTrue(result instanceof Part[]);
Part[] parts = (Part[]) result;
assertThat(parts, Matchers.arrayWithSize(2));
assertEquals(2, parts.length);
assertEquals(parts[0], part1);
assertEquals(parts[1], part2);
}
@@ -302,8 +313,8 @@ public class RequestPartMethodArgumentResolverTests {
@Test // SPR-9079
public void isMultipartRequestPut() throws Exception {
this.multipartRequest.setMethod("PUT");
Object actual = resolver.resolveArgument(paramMultipartFile, null, webRequest, null);
assertSame(multipartFile1, actual);
Object actualValue = resolver.resolveArgument(paramMultipartFile, null, webRequest, null);
assertSame(multipartFile1, actualValue);
}
@Test
@@ -311,12 +322,16 @@ public class RequestPartMethodArgumentResolverTests {
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
MultipartFile expected = new MockMultipartFile("optionalMultipartFile", "Hello World".getBytes());
request.addFile(expected);
request.addFile(new MockMultipartFile("otherPart", "", "text/plain", "Hello World".getBytes()));
webRequest = new ServletWebRequest(request);
Object result = resolver.resolveArgument(optionalMultipartFile, null, webRequest, null);
Object actualValue = resolver.resolveArgument(optionalMultipartFile, null, webRequest, null);
assertTrue(actualValue instanceof Optional);
assertEquals("Invalid result", expected, ((Optional) actualValue).get());
assertTrue(result instanceof Optional);
assertEquals("Invalid result", expected, ((Optional) result).get());
actualValue = resolver.resolveArgument(optionalMultipartFile, null, webRequest, null);
assertTrue(actualValue instanceof Optional);
assertEquals("Invalid result", expected, ((Optional) actualValue).get());
}
@Test
@@ -324,10 +339,62 @@ public class RequestPartMethodArgumentResolverTests {
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
webRequest = new ServletWebRequest(request);
Object result = resolver.resolveArgument(optionalMultipartFile, null, webRequest, null);
Object actualValue = resolver.resolveArgument(optionalMultipartFile, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
assertTrue(result instanceof Optional);
assertFalse("Invalid result", ((Optional) result).isPresent());
actualValue = resolver.resolveArgument(optionalMultipartFile, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
}
@Test
public void resolveOptionalMultipartFileArgumentWithoutMultipartRequest() throws Exception {
webRequest = new ServletWebRequest(new MockHttpServletRequest());
Object actualValue = resolver.resolveArgument(optionalMultipartFile, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
actualValue = resolver.resolveArgument(optionalMultipartFile, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
}
@Test
public void resolveOptionalMultipartFileList() throws Exception {
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
MultipartFile expected = new MockMultipartFile("requestPart", "Hello World".getBytes());
request.addFile(expected);
request.addFile(new MockMultipartFile("otherPart", "", "text/plain", "Hello World".getBytes()));
webRequest = new ServletWebRequest(request);
Object actualValue = resolver.resolveArgument(optionalMultipartFileList, null, webRequest, null);
assertTrue(actualValue instanceof Optional);
assertEquals("Invalid result", Collections.singletonList(expected), ((Optional) actualValue).get());
actualValue = resolver.resolveArgument(optionalMultipartFileList, null, webRequest, null);
assertTrue(actualValue instanceof Optional);
assertEquals("Invalid result", Collections.singletonList(expected), ((Optional) actualValue).get());
}
@Test
public void resolveOptionalMultipartFileListNotPresent() throws Exception {
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
webRequest = new ServletWebRequest(request);
Object actualValue = resolver.resolveArgument(optionalMultipartFileList, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
actualValue = resolver.resolveArgument(optionalMultipartFileList, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
}
@Test
public void resolveOptionalMultipartFileListWithoutMultipartRequest() throws Exception {
webRequest = new ServletWebRequest(new MockHttpServletRequest());
Object actualValue = resolver.resolveArgument(optionalMultipartFileList, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
actualValue = resolver.resolveArgument(optionalMultipartFileList, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
}
@Test
@@ -337,12 +404,16 @@ public class RequestPartMethodArgumentResolverTests {
request.setMethod("POST");
request.setContentType("multipart/form-data");
request.addPart(expected);
request.addPart(new MockPart("otherPart", "Hello World".getBytes()));
webRequest = new ServletWebRequest(request);
Object result = resolver.resolveArgument(optionalPart, null, webRequest, null);
Object actualValue = resolver.resolveArgument(optionalPart, null, webRequest, null);
assertTrue(actualValue instanceof Optional);
assertEquals("Invalid result", expected, ((Optional) actualValue).get());
assertTrue(result instanceof Optional);
assertEquals("Invalid result", expected, ((Optional) result).get());
actualValue = resolver.resolveArgument(optionalPart, null, webRequest, null);
assertTrue(actualValue instanceof Optional);
assertEquals("Invalid result", expected, ((Optional) actualValue).get());
}
@Test
@@ -352,36 +423,108 @@ public class RequestPartMethodArgumentResolverTests {
request.setContentType("multipart/form-data");
webRequest = new ServletWebRequest(request);
Object result = resolver.resolveArgument(optionalPart, null, webRequest, null);
Object actualValue = resolver.resolveArgument(optionalPart, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
assertTrue(result instanceof Optional);
assertFalse("Invalid result", ((Optional) result).isPresent());
actualValue = resolver.resolveArgument(optionalPart, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
}
@Test
public void resolveOptionalPartArgumentWithoutMultipartRequest() throws Exception {
webRequest = new ServletWebRequest(new MockHttpServletRequest());
Object actualValue = resolver.resolveArgument(optionalPart, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
actualValue = resolver.resolveArgument(optionalPart, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
}
@Test
public void resolveOptionalPartList() throws Exception {
MockPart expected = new MockPart("requestPart", "Hello World".getBytes());
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContentType("multipart/form-data");
request.addPart(expected);
request.addPart(new MockPart("otherPart", "Hello World".getBytes()));
webRequest = new ServletWebRequest(request);
Object actualValue = resolver.resolveArgument(optionalPartList, null, webRequest, null);
assertTrue(actualValue instanceof Optional);
assertEquals("Invalid result", Collections.singletonList(expected), ((Optional) actualValue).get());
actualValue = resolver.resolveArgument(optionalPartList, null, webRequest, null);
assertTrue(actualValue instanceof Optional);
assertEquals("Invalid result", Collections.singletonList(expected), ((Optional) actualValue).get());
}
@Test
public void resolveOptionalPartListNotPresent() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContentType("multipart/form-data");
webRequest = new ServletWebRequest(request);
Object actualValue = resolver.resolveArgument(optionalPartList, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
actualValue = resolver.resolveArgument(optionalPartList, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
}
@Test
public void resolveOptionalPartListWithoutMultipartRequest() throws Exception {
webRequest = new ServletWebRequest(new MockHttpServletRequest());
Object actualValue = resolver.resolveArgument(optionalPartList, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
actualValue = resolver.resolveArgument(optionalPartList, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
}
@Test
public void resolveOptionalRequestPart() throws Exception {
SimpleBean simpleBean = new SimpleBean("foo");
given(messageConverter.canRead(SimpleBean.class, MediaType.TEXT_PLAIN)).willReturn(true);
given(messageConverter.read(eq(SimpleBean.class), isA(HttpInputMessage.class))).willReturn(simpleBean);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
Object actualValue = resolver.resolveArgument(optionalRequestPart, mavContainer, webRequest, new ValidatingBinderFactory());
Object actualValue = resolver.resolveArgument(optionalRequestPart, mavContainer, webRequest, new ValidatingBinderFactory());
assertEquals("Invalid argument value", Optional.of(simpleBean), actualValue);
assertFalse("The requestHandled flag shouldn't change", mavContainer.isRequestHandled());
actualValue = resolver.resolveArgument(optionalRequestPart, mavContainer, webRequest, new ValidatingBinderFactory());
assertEquals("Invalid argument value", Optional.of(simpleBean), actualValue);
assertFalse("The requestHandled flag shouldn't change", mavContainer.isRequestHandled());
}
@Test
public void resolveOptionalRequestPartNotPresent() throws Exception {
given(messageConverter.canRead(SimpleBean.class, MediaType.TEXT_PLAIN)).willReturn(true);
given(messageConverter.read(eq(SimpleBean.class), isA(RequestPartServletServerHttpRequest.class))).willReturn(null);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
Object actualValue = resolver.resolveArgument(optionalRequestPart, mavContainer, webRequest, new ValidatingBinderFactory());
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setContentType("multipart/form-data");
webRequest = new ServletWebRequest(request);
Object actualValue = resolver.resolveArgument(optionalRequestPart, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
actualValue = resolver.resolveArgument(optionalRequestPart, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
}
@Test
public void resolveOptionalRequestPartWithoutMultipartRequest() throws Exception {
webRequest = new ServletWebRequest(new MockHttpServletRequest());
Object actualValue = resolver.resolveArgument(optionalRequestPart, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
actualValue = resolver.resolveArgument(optionalRequestPart, null, webRequest, null);
assertEquals("Invalid argument value", Optional.empty(), actualValue);
assertFalse("The requestHandled flag shouldn't change", mavContainer.isRequestHandled());
}
@@ -390,8 +533,8 @@ public class RequestPartMethodArgumentResolverTests {
given(messageConverter.read(eq(SimpleBean.class), isA(HttpInputMessage.class))).willReturn(argValue);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
Object actualValue = resolver.resolveArgument(parameter, mavContainer, webRequest, new ValidatingBinderFactory());
Object actualValue = resolver.resolveArgument(parameter, mavContainer, webRequest, new ValidatingBinderFactory());
assertEquals("Invalid argument value", argValue, actualValue);
assertFalse("The requestHandled flag shouldn't change", mavContainer.isRequestHandled());
}
@@ -425,22 +568,26 @@ public class RequestPartMethodArgumentResolverTests {
}
}
@SuppressWarnings("unused")
public void handle(@RequestPart SimpleBean requestPart,
@RequestPart(value="requestPart", required=false) SimpleBean namedRequestPart,
@Valid @RequestPart("requestPart") SimpleBean validRequestPart,
@RequestPart("requestPart") MultipartFile multipartFile,
@RequestPart("requestPart") List<MultipartFile> multipartFileList,
@RequestPart("requestPart") MultipartFile[] multipartFileArray,
int i,
MultipartFile multipartFileNotAnnot,
Part part,
@RequestPart("part") List<Part> partList,
@RequestPart("part") Part[] partArray,
@RequestParam MultipartFile requestParamAnnot,
Optional<MultipartFile> optionalMultipartFile,
Optional<Part> optionalPart,
@RequestPart("requestPart") Optional<SimpleBean> optionalRequestPart) {
public void handle(
@RequestPart SimpleBean requestPart,
@RequestPart(value="requestPart", required=false) SimpleBean namedRequestPart,
@Valid @RequestPart("requestPart") SimpleBean validRequestPart,
@RequestPart("requestPart") MultipartFile multipartFile,
@RequestPart("requestPart") List<MultipartFile> multipartFileList,
@RequestPart("requestPart") MultipartFile[] multipartFileArray,
int i,
MultipartFile multipartFileNotAnnot,
Part part,
@RequestPart("requestPart") List<Part> partList,
@RequestPart("requestPart") Part[] partArray,
@RequestParam MultipartFile requestParamAnnot,
Optional<MultipartFile> optionalMultipartFile,
@RequestPart("requestPart") Optional<List<MultipartFile>> optionalMultipartFileList,
Optional<Part> optionalPart,
@RequestPart("requestPart") Optional<List<Part>> optionalPartList,
@RequestPart("requestPart") Optional<SimpleBean> optionalRequestPart) {
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,7 +47,9 @@ import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMeth
import static org.junit.Assert.*;
/** @author Arjen Poutsma */
/**
* @author Arjen Poutsma
*/
public class DefaultHandlerExceptionResolverTests {
private DefaultHandlerExceptionResolver exceptionResolver;
@@ -174,7 +176,9 @@ public class DefaultHandlerExceptionResolverTests {
assertNotNull("No ModelAndView returned", mav);
assertTrue("No Empty ModelAndView returned", mav.isEmpty());
assertEquals("Invalid status code", 400, response.getStatus());
assertEquals("Required request part 'name' is not present.", response.getErrorMessage());
assertTrue(response.getErrorMessage().contains("request part"));
assertTrue(response.getErrorMessage().contains("name"));
assertTrue(response.getErrorMessage().contains("not present"));
}
@Test
@@ -211,6 +215,7 @@ public class DefaultHandlerExceptionResolverTests {
assertSame(ex, request.getAttribute("javax.servlet.error.exception"));
}
@SuppressWarnings("unused")
public void handle(String arg) {
}