Skip to content

Commit c5833b1

Browse files
committed
SPR-7353 Use canWrite to narrow down list of producible types
1 parent d02e37a commit c5833b1

File tree

3 files changed

+52
-11
lines changed

3 files changed

+52
-11
lines changed

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodProcessor.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,10 @@ protected <T> void writeWithMessageConverters(T returnValue,
164164
ServletServerHttpResponse outputMessage)
165165
throws IOException, HttpMediaTypeNotAcceptableException {
166166

167+
Class<?> returnValueClass = returnValue.getClass();
168+
167169
List<MediaType> acceptableMediaTypes = getAcceptableMediaTypes(inputMessage);
168-
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(inputMessage.getServletRequest());
170+
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(inputMessage.getServletRequest(), returnValueClass);
169171

170172
Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
171173
for (MediaType a : acceptableMediaTypes) {
@@ -196,7 +198,7 @@ else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICAT
196198

197199
if (selectedMediaType != null) {
198200
for (HttpMessageConverter<?> messageConverter : messageConverters) {
199-
if (messageConverter.canWrite(returnValue.getClass(), selectedMediaType)) {
201+
if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
200202
((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
201203
if (logger.isDebugEnabled()) {
202204
logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" +
@@ -213,23 +215,28 @@ else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICAT
213215
* Returns the media types that can be produced:
214216
* <ul>
215217
* <li>The producible media types specified in the request mappings, or
216-
* <li>The media types supported by all configured message converters, or
218+
* <li>Media types of configured converters that can write the specific return value, or
217219
* <li>{@link MediaType#ALL}
218220
* </ul>
219221
*/
220222
@SuppressWarnings("unchecked")
221-
protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request) {
223+
protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request, Class<?> returnValueClass) {
222224
Set<MediaType> mediaTypes = (Set<MediaType>) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
223225
if (!CollectionUtils.isEmpty(mediaTypes)) {
224226
return new ArrayList<MediaType>(mediaTypes);
225227
}
226228
else if (!allSupportedMediaTypes.isEmpty()) {
227-
return allSupportedMediaTypes;
229+
List<MediaType> result = new ArrayList<MediaType>();
230+
for (HttpMessageConverter<?> converter : messageConverters) {
231+
if (converter.canWrite(returnValueClass, null)) {
232+
result.addAll(converter.getSupportedMediaTypes());
233+
}
234+
}
235+
return result;
228236
}
229237
else {
230238
return Collections.singletonList(MediaType.ALL);
231239
}
232-
233240
}
234241

235242
private List<MediaType> getAcceptableMediaTypes(HttpInputMessage inputMessage) {

org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessorTests.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@
1515
*/
1616

1717
package org.springframework.web.servlet.mvc.method.annotation.support;
18+
import static org.easymock.EasyMock.capture;
19+
import static org.easymock.EasyMock.createMock;
20+
import static org.easymock.EasyMock.eq;
21+
import static org.easymock.EasyMock.expect;
22+
import static org.easymock.EasyMock.isA;
23+
import static org.easymock.EasyMock.replay;
24+
import static org.easymock.EasyMock.reset;
25+
import static org.easymock.EasyMock.verify;
26+
import static org.junit.Assert.assertEquals;
27+
import static org.junit.Assert.assertFalse;
28+
import static org.junit.Assert.assertTrue;
29+
import static org.junit.Assert.fail;
1830
import static org.springframework.web.servlet.HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE;
1931

2032
import java.lang.reflect.Method;
@@ -24,7 +36,6 @@
2436
import org.easymock.Capture;
2537
import org.junit.Before;
2638
import org.junit.Test;
27-
2839
import org.springframework.core.MethodParameter;
2940
import org.springframework.http.HttpEntity;
3041
import org.springframework.http.HttpHeaders;
@@ -41,10 +52,6 @@
4152
import org.springframework.web.bind.annotation.RequestMapping;
4253
import org.springframework.web.context.request.ServletWebRequest;
4354
import org.springframework.web.method.support.ModelAndViewContainer;
44-
import org.springframework.web.servlet.HandlerMapping;
45-
46-
import static org.easymock.EasyMock.*;
47-
import static org.junit.Assert.*;
4855

4956
/**
5057
* Test fixture with {@link HttpEntityMethodProcessor} and mock {@link HttpMessageConverter}.
@@ -164,6 +171,8 @@ public void handleReturnValue() throws Exception {
164171
MediaType accepted = MediaType.TEXT_PLAIN;
165172
servletRequest.addHeader("Accept", accepted.toString());
166173

174+
expect(messageConverter.canWrite(String.class, null)).andReturn(true);
175+
expect(messageConverter.getSupportedMediaTypes()).andReturn(Collections.singletonList(MediaType.TEXT_PLAIN));
167176
expect(messageConverter.canWrite(String.class, accepted)).andReturn(true);
168177
messageConverter.write(eq(body), eq(accepted), isA(HttpOutputMessage.class));
169178
replay(messageConverter);
@@ -218,6 +227,8 @@ public void handleReturnValueNotAcceptableProduces() throws Exception {
218227
MediaType accepted = MediaType.TEXT_PLAIN;
219228
servletRequest.addHeader("Accept", accepted.toString());
220229

230+
expect(messageConverter.canWrite(String.class, null)).andReturn(true);
231+
expect(messageConverter.getSupportedMediaTypes()).andReturn(Collections.singletonList(MediaType.TEXT_PLAIN));
221232
expect(messageConverter.canWrite(String.class, accepted)).andReturn(false);
222233
replay(messageConverter);
223234

@@ -245,6 +256,8 @@ public void responseHeaderAndBody() throws Exception {
245256
ResponseEntity<String> returnValue = new ResponseEntity<String>("body", responseHeaders, HttpStatus.ACCEPTED);
246257

247258
Capture<HttpOutputMessage> outputMessage = new Capture<HttpOutputMessage>();
259+
expect(messageConverter.canWrite(String.class, null)).andReturn(true);
260+
expect(messageConverter.getSupportedMediaTypes()).andReturn(Collections.singletonList(MediaType.TEXT_PLAIN));
248261
expect(messageConverter.canWrite(String.class, MediaType.TEXT_PLAIN)).andReturn(true);
249262
messageConverter.write(eq("body"), eq(MediaType.TEXT_PLAIN), capture(outputMessage));
250263
replay(messageConverter);

org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessorTests.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
package org.springframework.web.servlet.mvc.method.annotation.support;
1818

1919
import java.lang.reflect.Method;
20+
import java.util.ArrayList;
2021
import java.util.Arrays;
2122
import java.util.Collections;
23+
import java.util.List;
2224

2325
import org.junit.Before;
2426
import org.junit.Test;
@@ -27,7 +29,9 @@
2729
import org.springframework.http.HttpInputMessage;
2830
import org.springframework.http.HttpOutputMessage;
2931
import org.springframework.http.MediaType;
32+
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
3033
import org.springframework.http.converter.HttpMessageConverter;
34+
import org.springframework.http.converter.StringHttpMessageConverter;
3135
import org.springframework.mock.web.MockHttpServletRequest;
3236
import org.springframework.mock.web.MockHttpServletResponse;
3337
import org.springframework.web.HttpMediaTypeNotAcceptableException;
@@ -151,6 +155,8 @@ public void handleReturnValue() throws Exception {
151155
servletRequest.addHeader("Accept", accepted.toString());
152156

153157
String body = "Foo";
158+
expect(messageConverter.canWrite(String.class, null)).andReturn(true);
159+
expect(messageConverter.getSupportedMediaTypes()).andReturn(Collections.singletonList(MediaType.TEXT_PLAIN));
154160
expect(messageConverter.canWrite(String.class, accepted)).andReturn(true);
155161
messageConverter.write(eq(body), eq(accepted), isA(HttpOutputMessage.class));
156162
replay(messageConverter);
@@ -199,6 +205,8 @@ public void handleReturnValueNotAcceptableProduces() throws Exception {
199205
MediaType accepted = MediaType.TEXT_PLAIN;
200206
servletRequest.addHeader("Accept", accepted.toString());
201207

208+
expect(messageConverter.canWrite(String.class, null)).andReturn(true);
209+
expect(messageConverter.getSupportedMediaTypes()).andReturn(Collections.singletonList(MediaType.TEXT_PLAIN));
202210
expect(messageConverter.canWrite(String.class, accepted)).andReturn(false);
203211
replay(messageConverter);
204212

@@ -207,6 +215,19 @@ public void handleReturnValueNotAcceptableProduces() throws Exception {
207215
fail("Expected exception");
208216
}
209217

218+
@Test
219+
public void handleStringReturnValue() throws Exception {
220+
List<HttpMessageConverter<?>>converters = new ArrayList<HttpMessageConverter<?>>();
221+
converters.add(new ByteArrayHttpMessageConverter());
222+
converters.add(new StringHttpMessageConverter());
223+
224+
processor = new RequestResponseBodyMethodProcessor(converters);
225+
processor.handleReturnValue("Foo", returnTypeString, mavContainer, webRequest);
226+
227+
assertEquals("text/plain;charset=ISO-8859-1", servletResponse.getHeader("Content-Type"));
228+
assertEquals("Foo", servletResponse.getContentAsString());
229+
}
230+
210231
@ResponseBody
211232
public String handle1(@RequestBody String s, int i) {
212233
return s;

0 commit comments

Comments
 (0)