diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodProcessor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodProcessor.java index bcb48a747ce..2b7e6506630 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodProcessor.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodProcessor.java @@ -164,8 +164,10 @@ public abstract class AbstractMessageConverterMethodProcessor ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException { + Class returnValueClass = returnValue.getClass(); + List acceptableMediaTypes = getAcceptableMediaTypes(inputMessage); - List producibleMediaTypes = getProducibleMediaTypes(inputMessage.getServletRequest()); + List producibleMediaTypes = getProducibleMediaTypes(inputMessage.getServletRequest(), returnValueClass); Set compatibleMediaTypes = new LinkedHashSet(); for (MediaType a : acceptableMediaTypes) { @@ -196,7 +198,7 @@ public abstract class AbstractMessageConverterMethodProcessor if (selectedMediaType != null) { for (HttpMessageConverter messageConverter : messageConverters) { - if (messageConverter.canWrite(returnValue.getClass(), selectedMediaType)) { + if (messageConverter.canWrite(returnValueClass, selectedMediaType)) { ((HttpMessageConverter) messageConverter).write(returnValue, selectedMediaType, outputMessage); if (logger.isDebugEnabled()) { logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" + @@ -213,23 +215,28 @@ public abstract class AbstractMessageConverterMethodProcessor * Returns the media types that can be produced: *
    *
  • The producible media types specified in the request mappings, or - *
  • The media types supported by all configured message converters, or + *
  • Media types of configured converters that can write the specific return value, or *
  • {@link MediaType#ALL} *
*/ @SuppressWarnings("unchecked") - protected List getProducibleMediaTypes(HttpServletRequest request) { + protected List getProducibleMediaTypes(HttpServletRequest request, Class returnValueClass) { Set mediaTypes = (Set) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); if (!CollectionUtils.isEmpty(mediaTypes)) { return new ArrayList(mediaTypes); } else if (!allSupportedMediaTypes.isEmpty()) { - return allSupportedMediaTypes; + List result = new ArrayList(); + for (HttpMessageConverter converter : messageConverters) { + if (converter.canWrite(returnValueClass, null)) { + result.addAll(converter.getSupportedMediaTypes()); + } + } + return result; } else { return Collections.singletonList(MediaType.ALL); } - } private List getAcceptableMediaTypes(HttpInputMessage inputMessage) { diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessorTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessorTests.java index 8aa4ac39084..f9a1b8c8dee 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessorTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessorTests.java @@ -15,6 +15,18 @@ */ package org.springframework.web.servlet.mvc.method.annotation.support; +import static org.easymock.EasyMock.capture; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.eq; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.isA; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.reset; +import static org.easymock.EasyMock.verify; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.springframework.web.servlet.HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE; import java.lang.reflect.Method; @@ -24,7 +36,6 @@ import java.util.Collections; import org.easymock.Capture; import org.junit.Before; import org.junit.Test; - import org.springframework.core.MethodParameter; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; @@ -41,10 +52,6 @@ import org.springframework.web.HttpMediaTypeNotSupportedException; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.method.support.ModelAndViewContainer; -import org.springframework.web.servlet.HandlerMapping; - -import static org.easymock.EasyMock.*; -import static org.junit.Assert.*; /** * Test fixture with {@link HttpEntityMethodProcessor} and mock {@link HttpMessageConverter}. @@ -164,6 +171,8 @@ public class HttpEntityMethodProcessorTests { MediaType accepted = MediaType.TEXT_PLAIN; servletRequest.addHeader("Accept", accepted.toString()); + expect(messageConverter.canWrite(String.class, null)).andReturn(true); + expect(messageConverter.getSupportedMediaTypes()).andReturn(Collections.singletonList(MediaType.TEXT_PLAIN)); expect(messageConverter.canWrite(String.class, accepted)).andReturn(true); messageConverter.write(eq(body), eq(accepted), isA(HttpOutputMessage.class)); replay(messageConverter); @@ -218,6 +227,8 @@ public class HttpEntityMethodProcessorTests { MediaType accepted = MediaType.TEXT_PLAIN; servletRequest.addHeader("Accept", accepted.toString()); + expect(messageConverter.canWrite(String.class, null)).andReturn(true); + expect(messageConverter.getSupportedMediaTypes()).andReturn(Collections.singletonList(MediaType.TEXT_PLAIN)); expect(messageConverter.canWrite(String.class, accepted)).andReturn(false); replay(messageConverter); @@ -245,6 +256,8 @@ public class HttpEntityMethodProcessorTests { ResponseEntity returnValue = new ResponseEntity("body", responseHeaders, HttpStatus.ACCEPTED); Capture outputMessage = new Capture(); + expect(messageConverter.canWrite(String.class, null)).andReturn(true); + expect(messageConverter.getSupportedMediaTypes()).andReturn(Collections.singletonList(MediaType.TEXT_PLAIN)); expect(messageConverter.canWrite(String.class, MediaType.TEXT_PLAIN)).andReturn(true); messageConverter.write(eq("body"), eq(MediaType.TEXT_PLAIN), capture(outputMessage)); replay(messageConverter); diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessorTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessorTests.java index d5c3ab78f53..376334ba1c6 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessorTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessorTests.java @@ -17,8 +17,10 @@ package org.springframework.web.servlet.mvc.method.annotation.support; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.List; import org.junit.Before; import org.junit.Test; @@ -27,7 +29,9 @@ import org.springframework.core.MethodParameter; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; 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.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.web.HttpMediaTypeNotAcceptableException; @@ -151,6 +155,8 @@ public class RequestResponseBodyMethodProcessorTests { servletRequest.addHeader("Accept", accepted.toString()); String body = "Foo"; + expect(messageConverter.canWrite(String.class, null)).andReturn(true); + expect(messageConverter.getSupportedMediaTypes()).andReturn(Collections.singletonList(MediaType.TEXT_PLAIN)); expect(messageConverter.canWrite(String.class, accepted)).andReturn(true); messageConverter.write(eq(body), eq(accepted), isA(HttpOutputMessage.class)); replay(messageConverter); @@ -199,6 +205,8 @@ public class RequestResponseBodyMethodProcessorTests { MediaType accepted = MediaType.TEXT_PLAIN; servletRequest.addHeader("Accept", accepted.toString()); + expect(messageConverter.canWrite(String.class, null)).andReturn(true); + expect(messageConverter.getSupportedMediaTypes()).andReturn(Collections.singletonList(MediaType.TEXT_PLAIN)); expect(messageConverter.canWrite(String.class, accepted)).andReturn(false); replay(messageConverter); @@ -207,6 +215,19 @@ public class RequestResponseBodyMethodProcessorTests { fail("Expected exception"); } + @Test + public void handleStringReturnValue() throws Exception { + List>converters = new ArrayList>(); + converters.add(new ByteArrayHttpMessageConverter()); + converters.add(new StringHttpMessageConverter()); + + processor = new RequestResponseBodyMethodProcessor(converters); + processor.handleReturnValue("Foo", returnTypeString, mavContainer, webRequest); + + assertEquals("text/plain;charset=ISO-8859-1", servletResponse.getHeader("Content-Type")); + assertEquals("Foo", servletResponse.getContentAsString()); + } + @ResponseBody public String handle1(@RequestBody String s, int i) { return s;