89
89
* {@link #setFavorPathExtension(boolean) favorPathExtension} and
90
90
* {@link #setIgnoreUnknownPathExtensions(boolean) ignoreUnknownPathExtensions}
91
91
* are deprecated in order to discourage use of path extensions for content
92
- * negotiation and for request mapping (with similar deprecations in
92
+ * negotiation as well as for request mapping (with similar deprecations in
93
93
* {@link org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
94
94
* RequestMappingHandlerMapping}). For further context, please read issue
95
95
* <a href="https://github.com/spring-projects/spring-framework/issues/24179">#24719</a>.
@@ -157,46 +157,52 @@ public void setFavorPathExtension(boolean favorPathExtension) {
157
157
}
158
158
159
159
/**
160
- * Add a mapping from a key, extracted from a path extension or a query
161
- * parameter, to a MediaType. This is required in order for the parameter
162
- * strategy to work. Any extensions explicitly registered here are also
163
- * whitelisted for the purpose of Reflected File Download attack detection
164
- * (see Spring Framework reference documentation for more details on RFD
165
- * attack protection).
166
- * <p>The path extension strategy will also try to use
160
+ * Add a mapping from a key to a MediaType where the key are normalized to
161
+ * lowercase and may have been extracted from a path extension, a filename
162
+ * extension, or passed as a query parameter.
163
+ * <p>The {@link #setFavorParameter(boolean) parameter strategy} requires
164
+ * such mappings in order to work while the {@link #setFavorPathExtension(boolean)
165
+ * path extension strategy} can fall back on lookups via
167
166
* {@link ServletContext#getMimeType} and
168
- * {@link org.springframework.http.MediaTypeFactory} to resolve path extensions.
167
+ * {@link org.springframework.http.MediaTypeFactory}.
168
+ * <p><strong>Note:</strong> Mappings registered here may be accessed via
169
+ * {@link ContentNegotiationManager#getMediaTypeMappings()} and may be used
170
+ * not only in the parameter and path extension strategies. For example,
171
+ * with the Spring MVC config, e.g. {@code @EnableWebMvc} or
172
+ * {@code <mvc:annotation-driven>}, the media type mappings are also plugged
173
+ * in to:
174
+ * <ul>
175
+ * <li>Determine the media type of static resources served with
176
+ * {@code ResourceHttpRequestHandler}.
177
+ * <li>Determine the media type of views rendered with
178
+ * {@code ContentNegotiatingViewResolver}.
179
+ * <li>Whitelist extensions for RFD attack detection (check the Spring
180
+ * Framework reference docs for details).
181
+ * </ul>
169
182
* @param mediaTypes media type mappings
170
183
* @see #addMediaType(String, MediaType)
171
184
* @see #addMediaTypes(Map)
172
185
*/
173
186
public void setMediaTypes (Properties mediaTypes ) {
174
187
if (!CollectionUtils .isEmpty (mediaTypes )) {
175
- mediaTypes .forEach ((key , value ) -> {
176
- String extension = ((String ) key ).toLowerCase (Locale .ENGLISH );
177
- MediaType mediaType = MediaType .valueOf ((String ) value );
178
- this .mediaTypes .put (extension , mediaType );
179
- });
188
+ mediaTypes .forEach ((key , value ) ->
189
+ addMediaType ((String ) key , MediaType .valueOf ((String ) value )));
180
190
}
181
191
}
182
192
183
193
/**
184
- * An alternative to {@link #setMediaTypes} for use in Java code.
185
- * @see #setMediaTypes
186
- * @see #addMediaTypes
194
+ * An alternative to {@link #setMediaTypes} for programmatic registrations.
187
195
*/
188
- public void addMediaType (String fileExtension , MediaType mediaType ) {
189
- this .mediaTypes .put (fileExtension , mediaType );
196
+ public void addMediaType (String key , MediaType mediaType ) {
197
+ this .mediaTypes .put (key . toLowerCase ( Locale . ENGLISH ) , mediaType );
190
198
}
191
199
192
200
/**
193
- * An alternative to {@link #setMediaTypes} for use in Java code.
194
- * @see #setMediaTypes
195
- * @see #addMediaType
201
+ * An alternative to {@link #setMediaTypes} for programmatic registrations.
196
202
*/
197
203
public void addMediaTypes (@ Nullable Map <String , MediaType > mediaTypes ) {
198
204
if (mediaTypes != null ) {
199
- this . mediaTypes .putAll ( mediaTypes );
205
+ mediaTypes .forEach ( this :: addMediaType );
200
206
}
201
207
}
202
208
@@ -315,6 +321,7 @@ public void afterPropertiesSet() {
315
321
* Create and initialize a {@link ContentNegotiationManager} instance.
316
322
* @since 5.0
317
323
*/
324
+ @ SuppressWarnings ("deprecation" )
318
325
public ContentNegotiationManager build () {
319
326
List <ContentNegotiationStrategy > strategies = new ArrayList <>();
320
327
@@ -336,7 +343,6 @@ public ContentNegotiationManager build() {
336
343
}
337
344
strategies .add (strategy );
338
345
}
339
-
340
346
if (this .favorParameter ) {
341
347
ParameterContentNegotiationStrategy strategy = new ParameterContentNegotiationStrategy (this .mediaTypes );
342
348
strategy .setParameterName (this .parameterName );
@@ -348,17 +354,24 @@ public ContentNegotiationManager build() {
348
354
}
349
355
strategies .add (strategy );
350
356
}
351
-
352
357
if (!this .ignoreAcceptHeader ) {
353
358
strategies .add (new HeaderContentNegotiationStrategy ());
354
359
}
355
-
356
360
if (this .defaultNegotiationStrategy != null ) {
357
361
strategies .add (this .defaultNegotiationStrategy );
358
362
}
359
363
}
360
364
361
365
this .contentNegotiationManager = new ContentNegotiationManager (strategies );
366
+
367
+ // Ensure media type mappings are available via ContentNegotiationManager#getMediaTypeMappings()
368
+ // independent of path extension or parameter strategies.
369
+
370
+ if (!CollectionUtils .isEmpty (this .mediaTypes ) && !this .favorPathExtension && !this .favorParameter ) {
371
+ this .contentNegotiationManager .addFileExtensionResolvers (
372
+ new MappingMediaTypeFileExtensionResolver (this .mediaTypes ));
373
+ }
374
+
362
375
return this .contentNegotiationManager ;
363
376
}
364
377
0 commit comments