@@ -116,9 +116,10 @@ protected <T> void writeWithMessageConverters(T returnValue, MethodParameter ret
116116			throws  IOException , HttpMediaTypeNotAcceptableException  {
117117
118118		Class <?> returnValueClass  = getReturnValueType (returnValue , returnType );
119+ 		Type  returnValueType  = getGenericType (returnType );
119120		HttpServletRequest  servletRequest  = inputMessage .getServletRequest ();
120121		List <MediaType > requestedMediaTypes  = getAcceptableMediaTypes (servletRequest );
121- 		List <MediaType > producibleMediaTypes  = getProducibleMediaTypes (servletRequest , returnValueClass );
122+ 		List <MediaType > producibleMediaTypes  = getProducibleMediaTypes (servletRequest , returnValueClass ,  returnValueType );
122123
123124		Assert .isTrue (returnValue  == null  || !producibleMediaTypes .isEmpty (),
124125				"No converter found for return value of type: "  + returnValueClass );
@@ -156,25 +157,30 @@ else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICAT
156157		if  (selectedMediaType  != null ) {
157158			selectedMediaType  = selectedMediaType .removeQualityValue ();
158159			for  (HttpMessageConverter <?> messageConverter  : this .messageConverters ) {
159- 				if  (messageConverter .canWrite (returnValueClass , selectedMediaType )) {
160+ 				if  (messageConverter  instanceof  GenericHttpMessageConverter ) {
161+ 					if  (((GenericHttpMessageConverter <T >) messageConverter ).canWrite (returnValueType ,
162+ 							returnValueClass , selectedMediaType )) {
163+ 						returnValue  = (T ) getAdvice ().beforeBodyWrite (returnValue , returnType , selectedMediaType ,
164+ 								(Class <? extends  HttpMessageConverter <?>>) messageConverter .getClass (),
165+ 								inputMessage , outputMessage );
166+ 						if  (returnValue  != null ) {
167+ 							((GenericHttpMessageConverter <T >) messageConverter ).write (returnValue ,
168+ 									returnValueType , selectedMediaType , outputMessage );
169+ 							if  (logger .isDebugEnabled ()) {
170+ 								logger .debug ("Written ["  + returnValue  + "] as \" "  +
171+ 										selectedMediaType  + "\"  using ["  + messageConverter  + "]" );
172+ 							}
173+ 						}
174+ 						return ;
175+ 					}
176+ 				}
177+ 				else  if  (messageConverter .canWrite (returnValueClass , selectedMediaType )) {
160178					returnValue  = (T ) getAdvice ().beforeBodyWrite (returnValue , returnType , selectedMediaType ,
161179							(Class <? extends  HttpMessageConverter <?>>) messageConverter .getClass (),
162180							inputMessage , outputMessage );
163181					if  (returnValue  != null ) {
164- 						if  (messageConverter  instanceof  GenericHttpMessageConverter ) {
165- 							Type  type ;
166- 							if  (HttpEntity .class .isAssignableFrom (returnType .getParameterType ())) {
167- 								returnType .increaseNestingLevel ();
168- 								type  = returnType .getNestedGenericParameterType ();
169- 							}
170- 							else  {
171- 								type  = returnType .getGenericParameterType ();
172- 							}
173- 							((GenericHttpMessageConverter <T >) messageConverter ).write (returnValue , type , selectedMediaType , outputMessage );
174- 						}
175- 						else  {
176- 							((HttpMessageConverter <T >) messageConverter ).write (returnValue , selectedMediaType , outputMessage );
177- 						}
182+ 						((HttpMessageConverter <T >) messageConverter ).write (returnValue ,
183+ 								selectedMediaType , outputMessage );
178184						if  (logger .isDebugEnabled ()) {
179185							logger .debug ("Written ["  + returnValue  + "] as \" "  +
180186									selectedMediaType  + "\"  using ["  + messageConverter  + "]" );
@@ -200,24 +206,54 @@ protected Class<?> getReturnValueType(Object returnValue, MethodParameter return
200206		return  (returnValue  != null  ? returnValue .getClass () : returnType .getParameterType ());
201207	}
202208
209+ 	/** 
210+ 	 * Return the generic type of the {@code returnType} (or of the nested type if it is 
211+ 	 * a {@link HttpEntity}). 
212+ 	 */ 
213+ 	private  Type  getGenericType (MethodParameter  returnType ) {
214+ 		Type  type ;
215+ 		if  (HttpEntity .class .isAssignableFrom (returnType .getParameterType ())) {
216+ 			returnType .increaseNestingLevel ();
217+ 			type  = returnType .getNestedGenericParameterType ();
218+ 		}
219+ 		else  {
220+ 			type  = returnType .getGenericParameterType ();
221+ 		}
222+ 		return  type ;
223+ 	}
224+ 
225+ 	/** 
226+ 	 * @see #getProducibleMediaTypes(HttpServletRequest, Class, Type) 
227+ 	 */ 
228+ 	@ SuppressWarnings ("unchecked" )
229+ 	protected  List <MediaType > getProducibleMediaTypes (HttpServletRequest  request , Class <?> returnValueClass ) {
230+ 		return  getProducibleMediaTypes (request , returnValueClass , null );
231+ 	}
232+ 
203233	/** 
204234	 * Returns the media types that can be produced: 
205235	 * <ul> 
206236	 * <li>The producible media types specified in the request mappings, or 
207237	 * <li>Media types of configured converters that can write the specific return value, or 
208238	 * <li>{@link MediaType#ALL} 
209239	 * </ul> 
240+ 	 * @since 4.2 
210241	 */ 
211242	@ SuppressWarnings ("unchecked" )
212- 	protected  List <MediaType > getProducibleMediaTypes (HttpServletRequest  request , Class <?> returnValueClass ) {
243+ 	protected  List <MediaType > getProducibleMediaTypes (HttpServletRequest  request , Class <?> returnValueClass ,  Type   returnValueType ) {
213244		Set <MediaType > mediaTypes  = (Set <MediaType >) request .getAttribute (HandlerMapping .PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE );
214245		if  (!CollectionUtils .isEmpty (mediaTypes )) {
215246			return  new  ArrayList <MediaType >(mediaTypes );
216247		}
217248		else  if  (!this .allSupportedMediaTypes .isEmpty ()) {
218249			List <MediaType > result  = new  ArrayList <MediaType >();
219250			for  (HttpMessageConverter <?> converter  : this .messageConverters ) {
220- 				if  (converter .canWrite (returnValueClass , null )) {
251+ 				if  (converter  instanceof  GenericHttpMessageConverter  && returnValueType  != null ) {
252+ 					if  (((GenericHttpMessageConverter <?>) converter ).canWrite (returnValueType , returnValueClass , null )) {
253+ 						result .addAll (converter .getSupportedMediaTypes ());
254+ 					}
255+ 				}
256+ 				else  if  (converter .canWrite (returnValueClass , null )) {
221257					result .addAll (converter .getSupportedMediaTypes ());
222258				}
223259			}
0 commit comments