SPR-7353 Use canWrite to narrow down list of producible types

This commit is contained in:
Rossen Stoyanchev 2011-05-24 17:22:22 +00:00
parent d02e37a307
commit c5833b192e
3 changed files with 52 additions and 11 deletions

View File

@ -164,8 +164,10 @@ public abstract class AbstractMessageConverterMethodProcessor
ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException {
Class<?> returnValueClass = returnValue.getClass();
List<MediaType> acceptableMediaTypes = getAcceptableMediaTypes(inputMessage);
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(inputMessage.getServletRequest());
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(inputMessage.getServletRequest(), returnValueClass);
Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
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<T>) 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:
* <ul>
* <li>The producible media types specified in the request mappings, or
* <li>The media types supported by all configured message converters, or
* <li>Media types of configured converters that can write the specific return value, or
* <li>{@link MediaType#ALL}
* </ul>
*/
@SuppressWarnings("unchecked")
protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request) {
protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request, Class<?> returnValueClass) {
Set<MediaType> mediaTypes = (Set<MediaType>) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
if (!CollectionUtils.isEmpty(mediaTypes)) {
return new ArrayList<MediaType>(mediaTypes);
}
else if (!allSupportedMediaTypes.isEmpty()) {
return allSupportedMediaTypes;
List<MediaType> result = new ArrayList<MediaType>();
for (HttpMessageConverter<?> converter : messageConverters) {
if (converter.canWrite(returnValueClass, null)) {
result.addAll(converter.getSupportedMediaTypes());
}
}
return result;
}
else {
return Collections.singletonList(MediaType.ALL);
}
}
private List<MediaType> getAcceptableMediaTypes(HttpInputMessage inputMessage) {

View File

@ -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<String> returnValue = new ResponseEntity<String>("body", responseHeaders, HttpStatus.ACCEPTED);
Capture<HttpOutputMessage> outputMessage = new Capture<HttpOutputMessage>();
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);

View File

@ -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<HttpMessageConverter<?>>converters = new ArrayList<HttpMessageConverter<?>>();
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;