11/*
2- * Copyright 2002-2010 the original author or authors.
2+ * Copyright 2002-2011 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.
6666 * <p>This view resolver uses the requested {@linkplain MediaType media type} to select a suitable {@link View} for a
6767 * request. This media type is determined by using the following criteria:
6868 * <ol>
69- * <li>If the requested path has a file extension and if the {@link #setFavorPathExtension(boolean) } property is
69+ * <li>If the requested path has a file extension and if the {@link #setFavorPathExtension} property is
7070 * {@code true}, the {@link #setMediaTypes(Map) mediaTypes} property is inspected for a matching media type.</li>
71- * <li>If the request contains a parameter defining the extension and if the {@link #setFavorParameter(boolean) }
71+ * <li>If the request contains a parameter defining the extension and if the {@link #setFavorParameter}
7272 * property is <code>true</code>, the {@link #setMediaTypes(Map) mediaTypes} property is inspected for a matching
7373 * media type. The default name of the parameter is <code>format</code> and it can be configured using the
7474 * {@link #setParameterName(String) parameterName} property.</li>
7575 * <li>If there is no match in the {@link #setMediaTypes(Map) mediaTypes} property and if the Java Activation
76- * Framework (JAF) is both {@linkplain #setUseJaf(boolean) enabled} and present on the class path,
76+ * Framework (JAF) is both {@linkplain #setUseJaf enabled} and present on the class path,
7777 * {@link FileTypeMap#getContentType(String)} is used instead.</li>
7878 * <li>If the previous steps did not result in a media type, and
79- * {@link #setIgnoreAcceptHeader(boolean) ignoreAcceptHeader} is {@code false}, the request {@code Accept} header is
79+ * {@link #setIgnoreAcceptHeader ignoreAcceptHeader} is {@code false}, the request {@code Accept} header is
8080 * used.</li>
8181 * </ol>
8282 *
@@ -145,7 +145,7 @@ public int getOrder() {
145145 }
146146
147147 /**
148- * Indicates whether the extension of the request path should be used to determine the requested media type,
148+ * Indicate whether the extension of the request path should be used to determine the requested media type,
149149 * in favor of looking at the {@code Accept} header. The default value is {@code true}.
150150 * <p>For instance, when this flag is <code>true</code> (the default), a request for {@code /hotels.pdf}
151151 * will result in an {@code AbstractPdfView} being resolved, while the {@code Accept} header can be the
@@ -156,7 +156,7 @@ public void setFavorPathExtension(boolean favorPathExtension) {
156156 }
157157
158158 /**
159- * Indicates whether a request parameter should be used to determine the requested media type,
159+ * Indicate whether a request parameter should be used to determine the requested media type,
160160 * in favor of looking at the {@code Accept} header. The default value is {@code false}.
161161 * <p>For instance, when this flag is <code>true</code>, a request for {@code /hotels?format=pdf} will result
162162 * in an {@code AbstractPdfView} being resolved, while the {@code Accept} header can be the browser-defined
@@ -167,39 +167,38 @@ public void setFavorParameter(boolean favorParameter) {
167167 }
168168
169169 /**
170- * Sets the parameter name that can be used to determine the requested media type if the {@link
171- * #setFavorParameter(boolean) } property is {@code true}. The default parameter name is {@code format}.
170+ * Set the parameter name that can be used to determine the requested media type if the {@link
171+ * #setFavorParameter} property is {@code true}. The default parameter name is {@code format}.
172172 */
173173 public void setParameterName (String parameterName ) {
174174 this .parameterName = parameterName ;
175175 }
176176
177177 /**
178- * Indicates whether the HTTP {@code Accept} header should be ignored. Default is {@code false}.
179- * If set to {@code true}, this view resolver will only refer to the file extension and/or paramter,
180- * as indicated by the {@link #setFavorPathExtension(boolean) favorPathExtension} and
181- * {@link #setFavorParameter(boolean) favorParameter} properties.
178+ * Indicate whether the HTTP {@code Accept} header should be ignored. Default is {@code false}.
179+ * <p> If set to {@code true}, this view resolver will only refer to the file extension and/or
180+ * parameter, as indicated by the {@link #setFavorPathExtension favorPathExtension} and
181+ * {@link #setFavorParameter favorParameter} properties.
182182 */
183183 public void setIgnoreAcceptHeader (boolean ignoreAcceptHeader ) {
184184 this .ignoreAcceptHeader = ignoreAcceptHeader ;
185185 }
186186
187187 /**
188- * Indicates whether a {@link HttpServletResponse#SC_NOT_ACCEPTABLE 406 Not Acceptable} status code should be
189- * returned if no suitable view can be found.
190- *
188+ * Indicate whether a {@link HttpServletResponse#SC_NOT_ACCEPTABLE 406 Not Acceptable}
189+ * status code should be returned if no suitable view can be found.
191190 * <p>Default is {@code false}, meaning that this view resolver returns {@code null} for
192- * {@link #resolveViewName(String, Locale)} when an acceptable view cannot be found. This will allow for view
193- * resolvers chaining. When this property is set to {@code true},
194- * {@link #resolveViewName(String, Locale)} will respond with a view that sets the response status to
195- * {@code 406 Not Acceptable} instead.
191+ * {@link #resolveViewName(String, Locale)} when an acceptable view cannot be found.
192+ * This will allow for view resolvers chaining. When this property is set to {@code true},
193+ * {@link #resolveViewName(String, Locale)} will respond with a view that sets the
194+ * response status to {@code 406 Not Acceptable} instead.
196195 */
197196 public void setUseNotAcceptableStatusCode (boolean useNotAcceptableStatusCode ) {
198197 this .useNotAcceptableStatusCode = useNotAcceptableStatusCode ;
199198 }
200199
201200 /**
202- * Sets the mapping from file extensions to media types.
201+ * Set the mapping from file extensions to media types.
203202 * <p>When this mapping is not set or when an extension is not present, this view resolver
204203 * will fall back to using a {@link FileTypeMap} when the Java Action Framework is available.
205204 */
@@ -213,15 +212,15 @@ public void setMediaTypes(Map<String, String> mediaTypes) {
213212 }
214213
215214 /**
216- * Sets the default views to use when a more specific view can not be obtained
215+ * Set the default views to use when a more specific view can not be obtained
217216 * from the {@link ViewResolver} chain.
218217 */
219218 public void setDefaultViews (List <View > defaultViews ) {
220219 this .defaultViews = defaultViews ;
221220 }
222221
223222 /**
224- * Sets the default content type.
223+ * Set the default content type.
225224 * <p>This content type will be used when file extension, parameter, nor {@code Accept}
226225 * header define a content-type, either through being disabled or empty.
227226 */
@@ -230,7 +229,7 @@ public void setDefaultContentType(MediaType defaultContentType) {
230229 }
231230
232231 /**
233- * Indicates whether to use the Java Activation Framework to map from file extensions to media types.
232+ * Indicate whether to use the Java Activation Framework to map from file extensions to media types.
234233 * <p>Default is {@code true}, i.e. the Java Activation Framework is used (if available).
235234 */
236235 public void setUseJaf (boolean useJaf ) {
@@ -265,13 +264,38 @@ protected void initServletContext(ServletContext servletContext) {
265264 OrderComparator .sort (this .viewResolvers );
266265 }
267266
267+ public View resolveViewName (String viewName , Locale locale ) throws Exception {
268+ RequestAttributes attrs = RequestContextHolder .getRequestAttributes ();
269+ Assert .isInstanceOf (ServletRequestAttributes .class , attrs );
270+ List <MediaType > requestedMediaTypes = getMediaTypes (((ServletRequestAttributes ) attrs ).getRequest ());
271+ if (requestedMediaTypes != null ) {
272+ List <View > candidateViews = getCandidateViews (viewName , locale , requestedMediaTypes );
273+ View bestView = getBestView (candidateViews , requestedMediaTypes );
274+ if (bestView != null ) {
275+ return bestView ;
276+ }
277+ }
278+ if (this .useNotAcceptableStatusCode ) {
279+ if (logger .isDebugEnabled ()) {
280+ logger .debug ("No acceptable view found; returning 406 (Not Acceptable) status code" );
281+ }
282+ return NOT_ACCEPTABLE_VIEW ;
283+ }
284+ else {
285+ if (logger .isDebugEnabled ()) {
286+ logger .debug ("No acceptable view found; returning null" );
287+ }
288+ return null ;
289+ }
290+ }
291+
268292 /**
269293 * Determines the list of {@link MediaType} for the given {@link HttpServletRequest}.
270294 * <p>The default implementation invokes {@link #getMediaTypeFromFilename(String)} if {@linkplain
271- * #setFavorPathExtension(boolean) favorPathExtension} property is <code>true</code>. If the property is
272- * <code>false</code>, or when a media type cannot be determined from the request path, this method will
273- * inspect the {@code Accept} header of the request.
274- * <p>This method can be overriden to provide a different algorithm.
295+ * #setFavorPathExtension favorPathExtension} property is <code>true</code>. If the property is
296+ * <code>false</code>, or when a media type cannot be determined from the request path,
297+ * this method will inspect the {@code Accept} header of the request.
298+ * <p>This method can be overridden to provide a different algorithm.
275299 * @param request the current servlet request
276300 * @return the list of media types requested, if any
277301 */
@@ -303,12 +327,20 @@ protected List<MediaType> getMediaTypes(HttpServletRequest request) {
303327 if (!this .ignoreAcceptHeader ) {
304328 String acceptHeader = request .getHeader (ACCEPT_HEADER );
305329 if (StringUtils .hasText (acceptHeader )) {
306- List <MediaType > mediaTypes = MediaType .parseMediaTypes (acceptHeader );
307- MediaType .sortByQualityValue (mediaTypes );
308- if (logger .isDebugEnabled ()) {
309- logger .debug ("Requested media types are " + mediaTypes + " (based on Accept header)" );
330+ try {
331+ List <MediaType > mediaTypes = MediaType .parseMediaTypes (acceptHeader );
332+ MediaType .sortByQualityValue (mediaTypes );
333+ if (logger .isDebugEnabled ()) {
334+ logger .debug ("Requested media types are " + mediaTypes + " (based on Accept header)" );
335+ }
336+ return mediaTypes ;
337+ }
338+ catch (IllegalArgumentException ex ) {
339+ if (logger .isDebugEnabled ()) {
340+ logger .debug ("Could not parse accept header [" + acceptHeader + "]: " + ex .getMessage ());
341+ }
342+ return null ;
310343 }
311- return mediaTypes ;
312344 }
313345 }
314346 if (this .defaultContentType != null ) {
@@ -360,31 +392,6 @@ protected MediaType getMediaTypeFromParameter(String parameterValue) {
360392 return this .mediaTypes .get (parameterValue .toLowerCase (Locale .ENGLISH ));
361393 }
362394
363- public View resolveViewName (String viewName , Locale locale ) throws Exception {
364- RequestAttributes attrs = RequestContextHolder .getRequestAttributes ();
365- Assert .isInstanceOf (ServletRequestAttributes .class , attrs );
366- List <MediaType > requestedMediaTypes = getMediaTypes (((ServletRequestAttributes ) attrs ).getRequest ());
367- List <View > candidateViews = getCandidateViews (viewName , locale , requestedMediaTypes );
368- View bestView = getBestView (candidateViews , requestedMediaTypes );
369- if (bestView != null ) {
370- return bestView ;
371- }
372- else {
373- if (this .useNotAcceptableStatusCode ) {
374- if (logger .isDebugEnabled ()) {
375- logger .debug ("No acceptable view found; returning 406 (Not Acceptable) status code" );
376- }
377- return NOT_ACCEPTABLE_VIEW ;
378- }
379- else {
380- if (logger .isDebugEnabled ()) {
381- logger .debug ("No acceptable view found; returning null" );
382- }
383- return null ;
384- }
385- }
386- }
387-
388395 private List <View > getCandidateViews (String viewName , Locale locale , List <MediaType > requestedMediaTypes )
389396 throws Exception {
390397
@@ -414,7 +421,7 @@ private List<View> getCandidateViews(String viewName, Locale locale, List<MediaT
414421
415422 private List <String > getExtensionsForMediaType (MediaType requestedMediaType ) {
416423 List <String > result = new ArrayList <String >();
417- for (Entry <String , MediaType > entry : mediaTypes .entrySet ()) {
424+ for (Entry <String , MediaType > entry : this . mediaTypes .entrySet ()) {
418425 if (requestedMediaType .includes (entry .getValue ())) {
419426 result .add (entry .getKey ());
420427 }
@@ -438,9 +445,8 @@ private View getBestView(List<View> candidateViews, List<MediaType> requestedMed
438445 }
439446 if (bestView != null ) {
440447 if (logger .isDebugEnabled ()) {
441- logger .debug (
442- "Returning [" + bestView + "] based on requested media type '" + bestRequestedMediaType +
443- "'" );
448+ logger .debug ("Returning [" + bestView + "] based on requested media type '" +
449+ bestRequestedMediaType + "'" );
444450 }
445451 break ;
446452 }
@@ -495,7 +501,7 @@ private static FileTypeMap loadFileTypeMapFromContextSupportModule() {
495501
496502 public static MediaType getMediaType (String fileName ) {
497503 String mediaType = fileTypeMap .getContentType (fileName );
498- return StringUtils .hasText (mediaType ) ? MediaType .parseMediaType (mediaType ) : null ;
504+ return ( StringUtils .hasText (mediaType ) ? MediaType .parseMediaType (mediaType ) : null ) ;
499505 }
500506 }
501507
@@ -506,8 +512,7 @@ public String getContentType() {
506512 return null ;
507513 }
508514
509- public void render (Map <String , ?> model , HttpServletRequest request , HttpServletResponse response )
510- throws Exception {
515+ public void render (Map <String , ?> model , HttpServletRequest request , HttpServletResponse response ) {
511516 response .setStatus (HttpServletResponse .SC_NOT_ACCEPTABLE );
512517 }
513518 };
0 commit comments