SPR-7353 Use canWrite to narrow down list of producible types
This commit is contained in:
parent
d02e37a307
commit
c5833b192e
|
|
@ -164,8 +164,10 @@ public abstract class AbstractMessageConverterMethodProcessor
|
||||||
ServletServerHttpResponse outputMessage)
|
ServletServerHttpResponse outputMessage)
|
||||||
throws IOException, HttpMediaTypeNotAcceptableException {
|
throws IOException, HttpMediaTypeNotAcceptableException {
|
||||||
|
|
||||||
|
Class<?> returnValueClass = returnValue.getClass();
|
||||||
|
|
||||||
List<MediaType> acceptableMediaTypes = getAcceptableMediaTypes(inputMessage);
|
List<MediaType> acceptableMediaTypes = getAcceptableMediaTypes(inputMessage);
|
||||||
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(inputMessage.getServletRequest());
|
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(inputMessage.getServletRequest(), returnValueClass);
|
||||||
|
|
||||||
Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
|
Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
|
||||||
for (MediaType a : acceptableMediaTypes) {
|
for (MediaType a : acceptableMediaTypes) {
|
||||||
|
|
@ -196,7 +198,7 @@ public abstract class AbstractMessageConverterMethodProcessor
|
||||||
|
|
||||||
if (selectedMediaType != null) {
|
if (selectedMediaType != null) {
|
||||||
for (HttpMessageConverter<?> messageConverter : messageConverters) {
|
for (HttpMessageConverter<?> messageConverter : messageConverters) {
|
||||||
if (messageConverter.canWrite(returnValue.getClass(), selectedMediaType)) {
|
if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
|
||||||
((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
|
((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" +
|
logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" +
|
||||||
|
|
@ -213,23 +215,28 @@ public abstract class AbstractMessageConverterMethodProcessor
|
||||||
* Returns the media types that can be produced:
|
* Returns the media types that can be produced:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>The producible media types specified in the request mappings, or
|
* <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}
|
* <li>{@link MediaType#ALL}
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@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);
|
Set<MediaType> mediaTypes = (Set<MediaType>) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
|
||||||
if (!CollectionUtils.isEmpty(mediaTypes)) {
|
if (!CollectionUtils.isEmpty(mediaTypes)) {
|
||||||
return new ArrayList<MediaType>(mediaTypes);
|
return new ArrayList<MediaType>(mediaTypes);
|
||||||
}
|
}
|
||||||
else if (!allSupportedMediaTypes.isEmpty()) {
|
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 {
|
else {
|
||||||
return Collections.singletonList(MediaType.ALL);
|
return Collections.singletonList(MediaType.ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MediaType> getAcceptableMediaTypes(HttpInputMessage inputMessage) {
|
private List<MediaType> getAcceptableMediaTypes(HttpInputMessage inputMessage) {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,18 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.web.servlet.mvc.method.annotation.support;
|
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 static org.springframework.web.servlet.HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
@ -24,7 +36,6 @@ import java.util.Collections;
|
||||||
import org.easymock.Capture;
|
import org.easymock.Capture;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.http.HttpEntity;
|
import org.springframework.http.HttpEntity;
|
||||||
import org.springframework.http.HttpHeaders;
|
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.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.context.request.ServletWebRequest;
|
import org.springframework.web.context.request.ServletWebRequest;
|
||||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
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}.
|
* Test fixture with {@link HttpEntityMethodProcessor} and mock {@link HttpMessageConverter}.
|
||||||
|
|
@ -164,6 +171,8 @@ public class HttpEntityMethodProcessorTests {
|
||||||
MediaType accepted = MediaType.TEXT_PLAIN;
|
MediaType accepted = MediaType.TEXT_PLAIN;
|
||||||
servletRequest.addHeader("Accept", accepted.toString());
|
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);
|
expect(messageConverter.canWrite(String.class, accepted)).andReturn(true);
|
||||||
messageConverter.write(eq(body), eq(accepted), isA(HttpOutputMessage.class));
|
messageConverter.write(eq(body), eq(accepted), isA(HttpOutputMessage.class));
|
||||||
replay(messageConverter);
|
replay(messageConverter);
|
||||||
|
|
@ -218,6 +227,8 @@ public class HttpEntityMethodProcessorTests {
|
||||||
MediaType accepted = MediaType.TEXT_PLAIN;
|
MediaType accepted = MediaType.TEXT_PLAIN;
|
||||||
servletRequest.addHeader("Accept", accepted.toString());
|
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);
|
expect(messageConverter.canWrite(String.class, accepted)).andReturn(false);
|
||||||
replay(messageConverter);
|
replay(messageConverter);
|
||||||
|
|
||||||
|
|
@ -245,6 +256,8 @@ public class HttpEntityMethodProcessorTests {
|
||||||
ResponseEntity<String> returnValue = new ResponseEntity<String>("body", responseHeaders, HttpStatus.ACCEPTED);
|
ResponseEntity<String> returnValue = new ResponseEntity<String>("body", responseHeaders, HttpStatus.ACCEPTED);
|
||||||
|
|
||||||
Capture<HttpOutputMessage> outputMessage = new Capture<HttpOutputMessage>();
|
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);
|
expect(messageConverter.canWrite(String.class, MediaType.TEXT_PLAIN)).andReturn(true);
|
||||||
messageConverter.write(eq("body"), eq(MediaType.TEXT_PLAIN), capture(outputMessage));
|
messageConverter.write(eq("body"), eq(MediaType.TEXT_PLAIN), capture(outputMessage));
|
||||||
replay(messageConverter);
|
replay(messageConverter);
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,10 @@
|
||||||
package org.springframework.web.servlet.mvc.method.annotation.support;
|
package org.springframework.web.servlet.mvc.method.annotation.support;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
@ -27,7 +29,9 @@ import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.http.HttpInputMessage;
|
import org.springframework.http.HttpInputMessage;
|
||||||
import org.springframework.http.HttpOutputMessage;
|
import org.springframework.http.HttpOutputMessage;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
|
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||||
|
|
@ -151,6 +155,8 @@ public class RequestResponseBodyMethodProcessorTests {
|
||||||
servletRequest.addHeader("Accept", accepted.toString());
|
servletRequest.addHeader("Accept", accepted.toString());
|
||||||
|
|
||||||
String body = "Foo";
|
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);
|
expect(messageConverter.canWrite(String.class, accepted)).andReturn(true);
|
||||||
messageConverter.write(eq(body), eq(accepted), isA(HttpOutputMessage.class));
|
messageConverter.write(eq(body), eq(accepted), isA(HttpOutputMessage.class));
|
||||||
replay(messageConverter);
|
replay(messageConverter);
|
||||||
|
|
@ -199,6 +205,8 @@ public class RequestResponseBodyMethodProcessorTests {
|
||||||
MediaType accepted = MediaType.TEXT_PLAIN;
|
MediaType accepted = MediaType.TEXT_PLAIN;
|
||||||
servletRequest.addHeader("Accept", accepted.toString());
|
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);
|
expect(messageConverter.canWrite(String.class, accepted)).andReturn(false);
|
||||||
replay(messageConverter);
|
replay(messageConverter);
|
||||||
|
|
||||||
|
|
@ -207,6 +215,19 @@ public class RequestResponseBodyMethodProcessorTests {
|
||||||
fail("Expected exception");
|
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
|
@ResponseBody
|
||||||
public String handle1(@RequestBody String s, int i) {
|
public String handle1(@RequestBody String s, int i) {
|
||||||
return s;
|
return s;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue