Fix issue with generic @RequestBody arguments

The original commit c9b7b1 ensured the ability to read parameterized
type @RequestBody arguments via GenericHttpMessageConverter (e.g.
application/json and List<String>). However, it also affected the
ability to read @RequestBody arguments that happen are parameterized
but aren't treated as such (e.g. application/x-www-form-urlencoded and
MultiValueMap<String, String>). This commit corrects the issue.

Issue: SPR-9570
This commit is contained in:
Rossen Stoyanchev
2012-10-31 21:08:02 -04:00
parent 0e3aa0eec4
commit c0baea58c0
4 changed files with 101 additions and 36 deletions

View File

@@ -190,10 +190,9 @@ public class RequestResponseBodyMethodProcessorMockTests {
}
@Test(expected = HttpMediaTypeNotSupportedException.class)
public void resolveArgumentNotReadable() throws Exception {
public void resolveArgumentCannotRead() throws Exception {
MediaType contentType = MediaType.TEXT_PLAIN;
servletRequest.addHeader("Content-Type", contentType.toString());
servletRequest.setContent(new byte[] {});
expect(messageConverter.canRead(String.class, contentType)).andReturn(false);
replay(messageConverter);
@@ -201,19 +200,25 @@ public class RequestResponseBodyMethodProcessorMockTests {
processor.resolveArgument(paramRequestBodyString, mavContainer, webRequest, null);
}
@Test(expected = HttpMediaTypeNotSupportedException.class)
@Test
public void resolveArgumentNoContentType() throws Exception {
servletRequest.setContent(new byte[] {});
processor.resolveArgument(paramRequestBodyString, mavContainer, webRequest, null);
}
@Test(expected = HttpMessageNotReadableException.class)
public void resolveArgumentRequiredNoContent() throws Exception {
processor.resolveArgument(paramRequestBodyString, mavContainer, webRequest, null);
expect(messageConverter.canRead(String.class, MediaType.APPLICATION_OCTET_STREAM)).andReturn(false);
replay(messageConverter);
try {
processor.resolveArgument(paramRequestBodyString, mavContainer, webRequest, null);
fail("Expected exception");
}
catch (HttpMediaTypeNotSupportedException ex) {
}
verify(messageConverter);
}
@Test
public void resolveArgumentNotRequiredNoContent() throws Exception {
servletRequest.setContent(null);
assertNull(processor.resolveArgument(paramStringNotRequired, mavContainer, webRequest, new ValidatingBinderFactory()));
servletRequest.setContent(new byte[0]);
assertNull(processor.resolveArgument(paramStringNotRequired, mavContainer, webRequest, new ValidatingBinderFactory()));
}

View File

@@ -21,17 +21,21 @@ import static org.junit.Assert.assertNotNull;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.util.MultiValueMap;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.RequestBody;
@@ -52,6 +56,8 @@ public class RequestResponseBodyMethodProcessorTests {
private MethodParameter paramGenericList;
private MethodParameter paramSimpleBean;
private MethodParameter paramMultiValueMap;
private MethodParameter paramString;
private MethodParameter returnTypeString;
private ModelAndViewContainer mavContainer;
@@ -65,9 +71,13 @@ public class RequestResponseBodyMethodProcessorTests {
@Before
public void setUp() throws Exception {
Method method = getClass().getMethod("handle", List.class, SimpleBean.class);
Method method = getClass().getMethod("handle",
List.class, SimpleBean.class, MultiValueMap.class, String.class);
paramGenericList = new MethodParameter(method, 0);
paramSimpleBean = new MethodParameter(method, 1);
paramMultiValueMap = new MethodParameter(method, 2);
paramString = new MethodParameter(method, 3);
returnTypeString = new MethodParameter(method, -1);
mavContainer = new ModelAndViewContainer();
@@ -79,10 +89,10 @@ public class RequestResponseBodyMethodProcessorTests {
@Test
public void resolveGenericArgument() throws Exception {
public void resolveArgumentParameterizedType() throws Exception {
String content = "[{\"name\" : \"Jad\"}, {\"name\" : \"Robert\"}]";
this.servletRequest.setContent(content.getBytes("UTF-8"));
this.servletRequest.setContentType("application/json");
this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE);
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new MappingJackson2HttpMessageConverter());
@@ -98,7 +108,26 @@ public class RequestResponseBodyMethodProcessorTests {
}
@Test
public void resolveArgument() throws Exception {
public void resolveArgumentRawTypeFromParameterizedType() throws Exception {
String content = "fruit=apple&vegetable=kale";
this.servletRequest.setContent(content.getBytes("UTF-8"));
this.servletRequest.setContentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE);
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new XmlAwareFormHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
@SuppressWarnings("unchecked")
MultiValueMap<String, String> result = (MultiValueMap<String, String>) processor.resolveArgument(
paramMultiValueMap, mavContainer, webRequest, new ValidatingBinderFactory());
assertNotNull(result);
assertEquals("apple", result.getFirst("fruit"));
assertEquals("kale", result.getFirst("vegetable"));
}
@Test
public void resolveArgumentClassJson() throws Exception {
String content = "{\"name\" : \"Jad\"}";
this.servletRequest.setContent(content.getBytes("UTF-8"));
this.servletRequest.setContentType("application/json");
@@ -114,6 +143,23 @@ public class RequestResponseBodyMethodProcessorTests {
assertEquals("Jad", result.getName());
}
@Test
public void resolveArgumentClassString() throws Exception {
String content = "foobarbaz";
this.servletRequest.setContent(content.getBytes("UTF-8"));
this.servletRequest.setContentType("application/json");
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new StringHttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
String result = (String) processor.resolveArgument(
paramString, mavContainer, webRequest, new ValidatingBinderFactory());
assertNotNull(result);
assertEquals("foobarbaz", result);
}
// SPR-9160
@Test
@@ -158,7 +204,12 @@ public class RequestResponseBodyMethodProcessorTests {
}
public String handle(@RequestBody List<SimpleBean> list, @RequestBody SimpleBean simpleBean) {
public String handle(
@RequestBody List<SimpleBean> list,
@RequestBody SimpleBean simpleBean,
@RequestBody MultiValueMap<String, String> multiValueMap,
@RequestBody String string) {
return null;
}