11/*
2- * Copyright 2002-2015 the original author or authors.
2+ * Copyright 2002-2016 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
3030import javax .servlet .http .HttpServletResponse ;
3131
3232import org .springframework .core .MethodParameter ;
33+ import org .springframework .core .ResolvableType ;
3334import org .springframework .http .HttpEntity ;
3435import org .springframework .http .HttpHeaders ;
3536import org .springframework .http .HttpOutputMessage ;
6263public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver
6364 implements HandlerMethodReturnValueHandler {
6465
65- private static final MediaType MEDIA_TYPE_APPLICATION = new MediaType ("application" );
66-
67- private static final UrlPathHelper RAW_URL_PATH_HELPER = new UrlPathHelper ();
68-
69- private static final UrlPathHelper DECODING_URL_PATH_HELPER = new UrlPathHelper ();
70-
71- static {
72- RAW_URL_PATH_HELPER .setRemoveSemicolonContent (false );
73- RAW_URL_PATH_HELPER .setUrlDecode (false );
74- }
75-
7666 /* Extensions associated with the built-in message converters */
7767 private static final Set <String > WHITELISTED_EXTENSIONS = new HashSet <String >(Arrays .asList (
7868 "txt" , "text" , "yml" , "properties" , "csv" ,
@@ -82,6 +72,17 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
8272 private static final Set <String > WHITELISTED_MEDIA_BASE_TYPES = new HashSet <String >(
8373 Arrays .asList ("audio" , "image" , "video" ));
8474
75+ private static final MediaType MEDIA_TYPE_APPLICATION = new MediaType ("application" );
76+
77+ private static final UrlPathHelper DECODING_URL_PATH_HELPER = new UrlPathHelper ();
78+
79+ private static final UrlPathHelper RAW_URL_PATH_HELPER = new UrlPathHelper ();
80+
81+ static {
82+ RAW_URL_PATH_HELPER .setRemoveSemicolonContent (false );
83+ RAW_URL_PATH_HELPER .setUrlDecode (false );
84+ }
85+
8586
8687 private final ContentNegotiationManager contentNegotiationManager ;
8788
@@ -145,17 +146,17 @@ protected ServletServerHttpResponse createOutputMessage(NativeWebRequest webRequ
145146 * Writes the given return value to the given web request. Delegates to
146147 * {@link #writeWithMessageConverters(Object, MethodParameter, ServletServerHttpRequest, ServletServerHttpResponse)}
147148 */
148- protected <T > void writeWithMessageConverters (T returnValue , MethodParameter returnType , NativeWebRequest webRequest )
149+ protected <T > void writeWithMessageConverters (T value , MethodParameter returnType , NativeWebRequest webRequest )
149150 throws IOException , HttpMediaTypeNotAcceptableException , HttpMessageNotWritableException {
150151
151152 ServletServerHttpRequest inputMessage = createInputMessage (webRequest );
152153 ServletServerHttpResponse outputMessage = createOutputMessage (webRequest );
153- writeWithMessageConverters (returnValue , returnType , inputMessage , outputMessage );
154+ writeWithMessageConverters (value , returnType , inputMessage , outputMessage );
154155 }
155156
156157 /**
157158 * Writes the given return type to the given output message.
158- * @param returnValue the value to write to the output message
159+ * @param value the value to write to the output message
159160 * @param returnType the type of the value
160161 * @param inputMessage the input messages. Used to inspect the {@code Accept} header.
161162 * @param outputMessage the output message to write to
@@ -164,18 +165,18 @@ protected <T> void writeWithMessageConverters(T returnValue, MethodParameter ret
164165 * the request cannot be met by the message converters
165166 */
166167 @ SuppressWarnings ("unchecked" )
167- protected <T > void writeWithMessageConverters (T returnValue , MethodParameter returnType ,
168+ protected <T > void writeWithMessageConverters (T value , MethodParameter returnType ,
168169 ServletServerHttpRequest inputMessage , ServletServerHttpResponse outputMessage )
169170 throws IOException , HttpMediaTypeNotAcceptableException , HttpMessageNotWritableException {
170171
171- Class <?> returnValueClass = getReturnValueType (returnValue , returnType );
172- Type returnValueType = getGenericType (returnType );
173- HttpServletRequest servletRequest = inputMessage .getServletRequest ();
174- List <MediaType > requestedMediaTypes = getAcceptableMediaTypes (servletRequest );
175- List <MediaType > producibleMediaTypes = getProducibleMediaTypes (servletRequest , returnValueClass , returnValueType );
172+ Class <?> valueType = getReturnValueType (value , returnType );
173+ Type declaredType = getGenericType (returnType );
174+ HttpServletRequest request = inputMessage .getServletRequest ();
175+ List <MediaType > requestedMediaTypes = getAcceptableMediaTypes (request );
176+ List <MediaType > producibleMediaTypes = getProducibleMediaTypes (request , valueType , declaredType );
176177
177- if (returnValue != null && producibleMediaTypes .isEmpty ()) {
178- throw new IllegalArgumentException ("No converter found for return value of type: " + returnValueClass );
178+ if (value != null && producibleMediaTypes .isEmpty ()) {
179+ throw new IllegalArgumentException ("No converter found for return value of type: " + valueType );
179180 }
180181
181182 Set <MediaType > compatibleMediaTypes = new LinkedHashSet <MediaType >();
@@ -187,7 +188,7 @@ protected <T> void writeWithMessageConverters(T returnValue, MethodParameter ret
187188 }
188189 }
189190 if (compatibleMediaTypes .isEmpty ()) {
190- if (returnValue != null ) {
191+ if (value != null ) {
191192 throw new HttpMediaTypeNotAcceptableException (producibleMediaTypes );
192193 }
193194 return ;
@@ -212,78 +213,74 @@ else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICAT
212213 selectedMediaType = selectedMediaType .removeQualityValue ();
213214 for (HttpMessageConverter <?> messageConverter : this .messageConverters ) {
214215 if (messageConverter instanceof GenericHttpMessageConverter ) {
215- if (((GenericHttpMessageConverter <T >) messageConverter ).canWrite (returnValueType ,
216- returnValueClass , selectedMediaType )) {
217- returnValue = (T ) getAdvice ().beforeBodyWrite (returnValue , returnType , selectedMediaType ,
216+ if (((GenericHttpMessageConverter <T >) messageConverter ).canWrite (
217+ declaredType , valueType , selectedMediaType )) {
218+ value = (T ) getAdvice ().beforeBodyWrite (value , returnType , selectedMediaType ,
218219 (Class <? extends HttpMessageConverter <?>>) messageConverter .getClass (),
219220 inputMessage , outputMessage );
220- if (returnValue != null ) {
221+ if (value != null ) {
221222 addContentDispositionHeader (inputMessage , outputMessage );
222- ((GenericHttpMessageConverter <T >) messageConverter ).write (returnValue ,
223- returnValueType , selectedMediaType , outputMessage );
223+ ((GenericHttpMessageConverter <T >) messageConverter ).write (
224+ value , declaredType , selectedMediaType , outputMessage );
224225 if (logger .isDebugEnabled ()) {
225- logger .debug ("Written [" + returnValue + "] as \" " +
226- selectedMediaType + "\" using [" + messageConverter + "]" );
226+ logger .debug ("Written [" + value + "] as \" " + selectedMediaType +
227+ "\" using [" + messageConverter + "]" );
227228 }
228229 }
229230 return ;
230231 }
231232 }
232- else if (messageConverter .canWrite (returnValueClass , selectedMediaType )) {
233- returnValue = (T ) getAdvice ().beforeBodyWrite (returnValue , returnType , selectedMediaType ,
233+ else if (messageConverter .canWrite (valueType , selectedMediaType )) {
234+ value = (T ) getAdvice ().beforeBodyWrite (value , returnType , selectedMediaType ,
234235 (Class <? extends HttpMessageConverter <?>>) messageConverter .getClass (),
235236 inputMessage , outputMessage );
236- if (returnValue != null ) {
237+ if (value != null ) {
237238 addContentDispositionHeader (inputMessage , outputMessage );
238- ((HttpMessageConverter <T >) messageConverter ).write (returnValue ,
239- selectedMediaType , outputMessage );
239+ ((HttpMessageConverter <T >) messageConverter ).write (value , selectedMediaType , outputMessage );
240240 if (logger .isDebugEnabled ()) {
241- logger .debug ("Written [" + returnValue + "] as \" " +
242- selectedMediaType + "\" using [" + messageConverter + "]" );
241+ logger .debug ("Written [" + value + "] as \" " + selectedMediaType +
242+ "\" using [" + messageConverter + "]" );
243243 }
244244 }
245245 return ;
246246 }
247247 }
248248 }
249249
250- if (returnValue != null ) {
250+ if (value != null ) {
251251 throw new HttpMediaTypeNotAcceptableException (this .allSupportedMediaTypes );
252252 }
253253 }
254254
255255 /**
256- * Return the type of the value to be written to the response. Typically this
257- * is a simple check via getClass on the returnValue but if the returnValue is
258- * null, then the returnType needs to be examined possibly including generic
259- * type determination (e.g. {@code ResponseEntity<T>}).
256+ * Return the type of the value to be written to the response. Typically this is
257+ * a simple check via getClass on the value but if the value is null, then the
258+ * return type needs to be examined possibly including generic type determination
259+ * (e.g. {@code ResponseEntity<T>}).
260260 */
261- protected Class <?> getReturnValueType (Object returnValue , MethodParameter returnType ) {
262- return (returnValue != null ? returnValue .getClass () : returnType .getParameterType ());
261+ protected Class <?> getReturnValueType (Object value , MethodParameter returnType ) {
262+ return (value != null ? value .getClass () : returnType .getParameterType ());
263263 }
264264
265265 /**
266- * Return the generic type of the {@code returnType} (or of the nested type if it is
267- * a {@link HttpEntity}).
266+ * Return the generic type of the {@code returnType} (or of the nested type
267+ * if it is an {@link HttpEntity}).
268268 */
269269 private Type getGenericType (MethodParameter returnType ) {
270- Type type ;
271270 if (HttpEntity .class .isAssignableFrom (returnType .getParameterType ())) {
272- returnType .increaseNestingLevel ();
273- type = returnType .getNestedGenericParameterType ();
271+ return ResolvableType .forType (returnType .getGenericParameterType ()).getGeneric (0 ).getType ();
274272 }
275273 else {
276- type = returnType .getGenericParameterType ();
274+ return returnType .getGenericParameterType ();
277275 }
278- return type ;
279276 }
280277
281278 /**
282279 * @see #getProducibleMediaTypes(HttpServletRequest, Class, Type)
283280 */
284281 @ SuppressWarnings ({"unchecked" , "unused" })
285- protected List <MediaType > getProducibleMediaTypes (HttpServletRequest request , Class <?> returnValueClass ) {
286- return getProducibleMediaTypes (request , returnValueClass , null );
282+ protected List <MediaType > getProducibleMediaTypes (HttpServletRequest request , Class <?> valueClass ) {
283+ return getProducibleMediaTypes (request , valueClass , null );
287284 }
288285
289286 /**
@@ -296,20 +293,20 @@ protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request, Cl
296293 * @since 4.2
297294 */
298295 @ SuppressWarnings ("unchecked" )
299- protected List <MediaType > getProducibleMediaTypes (HttpServletRequest request , Class <?> returnValueClass , Type returnValueType ) {
296+ protected List <MediaType > getProducibleMediaTypes (HttpServletRequest request , Class <?> valueClass , Type declaredType ) {
300297 Set <MediaType > mediaTypes = (Set <MediaType >) request .getAttribute (HandlerMapping .PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE );
301298 if (!CollectionUtils .isEmpty (mediaTypes )) {
302299 return new ArrayList <MediaType >(mediaTypes );
303300 }
304301 else if (!this .allSupportedMediaTypes .isEmpty ()) {
305302 List <MediaType > result = new ArrayList <MediaType >();
306303 for (HttpMessageConverter <?> converter : this .messageConverters ) {
307- if (converter instanceof GenericHttpMessageConverter && returnValueType != null ) {
308- if (((GenericHttpMessageConverter <?>) converter ).canWrite (returnValueType , returnValueClass , null )) {
304+ if (converter instanceof GenericHttpMessageConverter && declaredType != null ) {
305+ if (((GenericHttpMessageConverter <?>) converter ).canWrite (declaredType , valueClass , null )) {
309306 result .addAll (converter .getSupportedMediaTypes ());
310307 }
311308 }
312- else if (converter .canWrite (returnValueClass , null )) {
309+ else if (converter .canWrite (valueClass , null )) {
313310 result .addAll (converter .getSupportedMediaTypes ());
314311 }
315312 }
@@ -412,7 +409,7 @@ private boolean safeMediaTypesForExtension(String extension) {
412409 try {
413410 mediaTypes = this .pathStrategy .resolveMediaTypeKey (null , extension );
414411 }
415- catch (HttpMediaTypeNotAcceptableException e ) {
412+ catch (HttpMediaTypeNotAcceptableException ex ) {
416413 // Ignore
417414 }
418415 if (CollectionUtils .isEmpty (mediaTypes )) {
0 commit comments