SPR-6877 - AnnotationMethodHandlerAdapter.handleResponseBody prioritizes messageConverter over MediaType

This commit is contained in:
Arjen Poutsma 2010-03-03 10:18:59 +00:00
parent 894875ce8d
commit 62f9f477f5
2 changed files with 73 additions and 7 deletions

View File

@ -871,10 +871,9 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
HttpOutputMessage outputMessage = new ServletServerHttpResponse(webRequest.getResponse());
Class<?> returnValueType = returnValue.getClass();
List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>();
if (messageConverters != null) {
for (HttpMessageConverter messageConverter : messageConverters) {
allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
for (MediaType acceptedMediaType : acceptedMediaTypes) {
if (getMessageConverters() != null) {
for (MediaType acceptedMediaType : acceptedMediaTypes) {
for (HttpMessageConverter messageConverter : getMessageConverters()) {
if (messageConverter.canWrite(returnValueType, acceptedMediaType)) {
messageConverter.write(returnValue, acceptedMediaType, outputMessage);
this.responseArgumentUsed = true;
@ -882,6 +881,9 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
}
}
}
for (HttpMessageConverter messageConverter : messageConverters) {
allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
}
}
throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes);
}

View File

@ -26,6 +26,7 @@ import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.security.Principal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
@ -1037,7 +1038,7 @@ public class ServletAnnotationControllerTests {
String requestBody = "Hello World";
request.setContent(requestBody.getBytes("UTF-8"));
request.addHeader("Content-Type", "text/plain; charset=utf-8");
request.addHeader("Accept", "text/*");
request.addHeader("Accept", "text/*, */*");
MockHttpServletResponse response = new MockHttpServletResponse();
servlet.service(request, response);
assertEquals(200, response.getStatus());
@ -1137,7 +1138,7 @@ public class ServletAnnotationControllerTests {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.registerBeanDefinition("controller", new RootBeanDefinition(RequestBodyController.class));
RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class);
adapterDef.getPropertyValues().add("messageConverters", new MyMessageConverter());
adapterDef.getPropertyValues().add("messageConverters", new NotReadableMessageConverter());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
wac.refresh();
return wac;
@ -1154,6 +1155,38 @@ public class ServletAnnotationControllerTests {
assertEquals("Invalid response status code", HttpServletResponse.SC_BAD_REQUEST, response.getStatus());
}
/*
* See SPR-6877
*/
@Test
public void overlappingMesssageConvertersRequestBody() throws ServletException, IOException {
@SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
@Override
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.registerBeanDefinition("controller", new RootBeanDefinition(RequestBodyController.class));
RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class);
List<HttpMessageConverter> messageConverters = new ArrayList<HttpMessageConverter>();
messageConverters.add(new StringHttpMessageConverter());
messageConverters
.add(new SimpleMessageConverter(new MediaType("application","json"), MediaType.ALL));
adapterDef.getPropertyValues().add("messageConverters", messageConverters);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
wac.refresh();
return wac;
}
};
servlet.init(new MockServletConfig());
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something");
request.setContent("Hello World".getBytes("UTF-8"));
request.addHeader("Content-Type", "text/plain; charset=utf-8");
request.addHeader("Accept", "application/json, text/javascript, */*");
MockHttpServletResponse response = new MockHttpServletResponse();
servlet.service(request, response);
assertEquals("Invalid response status code", "application/json", response.getHeader("Content-Type"));
}
@Test
public void headers() throws ServletException, IOException {
initServlet(HeadersController.class);
@ -2123,7 +2156,7 @@ public class ServletAnnotationControllerTests {
}
}
public static class MyMessageConverter implements HttpMessageConverter {
public static class NotReadableMessageConverter implements HttpMessageConverter {
public boolean canRead(Class clazz, MediaType mediaType) {
return true;
@ -2148,6 +2181,37 @@ public class ServletAnnotationControllerTests {
}
}
public static class SimpleMessageConverter implements HttpMessageConverter {
private final List<MediaType> supportedMediaTypes;
public SimpleMessageConverter(MediaType... supportedMediaTypes) {
this.supportedMediaTypes = Arrays.asList(supportedMediaTypes);
}
public boolean canRead(Class clazz, MediaType mediaType) {
return supportedMediaTypes.contains(mediaType);
}
public boolean canWrite(Class clazz, MediaType mediaType) {
return supportedMediaTypes.contains(mediaType);
}
public List getSupportedMediaTypes() {
return supportedMediaTypes;
}
public Object read(Class clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
return null;
}
public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
outputMessage.getHeaders().setContentType(contentType);
}
}
@Controller
public static class HeadersController {