1616
1717package org .springframework .web .servlet .config ;
1818
19+ import java .util .Arrays ;
20+ import java .util .HashMap ;
1921import java .util .List ;
22+ import java .util .Map ;
2023
2124import org .springframework .beans .factory .config .BeanDefinition ;
2225import org .springframework .beans .factory .config .BeanDefinitionHolder ;
2932import org .springframework .beans .factory .xml .ParserContext ;
3033import org .springframework .format .support .DefaultFormattingConversionService ;
3134import org .springframework .format .support .FormattingConversionServiceFactoryBean ;
35+ import org .springframework .http .MediaType ;
3236import org .springframework .http .converter .ByteArrayHttpMessageConverter ;
3337import org .springframework .http .converter .HttpMessageConverter ;
3438import org .springframework .http .converter .ResourceHttpMessageConverter ;
4448import org .springframework .util .xml .DomUtils ;
4549import org .springframework .validation .beanvalidation .LocalValidatorFactoryBean ;
4650import org .springframework .web .HttpRequestHandler ;
51+ import org .springframework .web .accept .ContentNegotiationManager ;
52+ import org .springframework .web .accept .HeaderContentNegotiationStrategy ;
53+ import org .springframework .web .accept .PathExtensionContentNegotiationStrategy ;
4754import org .springframework .web .bind .annotation .ExceptionHandler ;
4855import org .springframework .web .bind .annotation .ResponseStatus ;
4956import org .springframework .web .bind .support .ConfigurableWebBindingInitializer ;
102109 * </ul>
103110 *
104111 * <p>Both the {@link RequestMappingHandlerAdapter} and the
105- * {@link ExceptionHandlerExceptionResolver} are configured with default
106- * instances of the following kind, unless custom instances are provided :
112+ * {@link ExceptionHandlerExceptionResolver} are configured with instances of
113+ * the following by default :
107114 * <ul>
115+ * <li>A {@link ContentNegotiationManager}
108116 * <li>A {@link DefaultFormattingConversionService}
109117 * <li>A {@link LocalValidatorFactoryBean} if a JSR-303 implementation is
110118 * available on the classpath
@@ -143,11 +151,14 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
143151 CompositeComponentDefinition compDefinition = new CompositeComponentDefinition (element .getTagName (), source );
144152 parserContext .pushContainingComponent (compDefinition );
145153
146- RootBeanDefinition methodMappingDef = new RootBeanDefinition (RequestMappingHandlerMapping .class );
147- methodMappingDef .setSource (source );
148- methodMappingDef .setRole (BeanDefinition .ROLE_INFRASTRUCTURE );
149- methodMappingDef .getPropertyValues ().add ("order" , 0 );
150- String methodMappingName = parserContext .getReaderContext ().registerWithGeneratedName (methodMappingDef );
154+ RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager (element , source , parserContext );
155+
156+ RootBeanDefinition handlerMappingDef = new RootBeanDefinition (RequestMappingHandlerMapping .class );
157+ handlerMappingDef .setSource (source );
158+ handlerMappingDef .setRole (BeanDefinition .ROLE_INFRASTRUCTURE );
159+ handlerMappingDef .getPropertyValues ().add ("order" , 0 );
160+ handlerMappingDef .getPropertyValues ().add ("contentNegotiationManager" , contentNegotiationManager );
161+ String methodMappingName = parserContext .getReaderContext ().registerWithGeneratedName (handlerMappingDef );
151162
152163 RuntimeBeanReference conversionService = getConversionService (element , source , parserContext );
153164 RuntimeBeanReference validator = getValidator (element , source , parserContext );
@@ -164,22 +175,23 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
164175 ManagedList <?> argumentResolvers = getArgumentResolvers (element , source , parserContext );
165176 ManagedList <?> returnValueHandlers = getReturnValueHandlers (element , source , parserContext );
166177
167- RootBeanDefinition methodAdapterDef = new RootBeanDefinition (RequestMappingHandlerAdapter .class );
168- methodAdapterDef .setSource (source );
169- methodAdapterDef .setRole (BeanDefinition .ROLE_INFRASTRUCTURE );
170- methodAdapterDef .getPropertyValues ().add ("webBindingInitializer" , bindingDef );
171- methodAdapterDef .getPropertyValues ().add ("messageConverters" , messageConverters );
178+ RootBeanDefinition handlerAdapterDef = new RootBeanDefinition (RequestMappingHandlerAdapter .class );
179+ handlerAdapterDef .setSource (source );
180+ handlerAdapterDef .setRole (BeanDefinition .ROLE_INFRASTRUCTURE );
181+ handlerAdapterDef .getPropertyValues ().add ("contentNegotiationManager" , contentNegotiationManager );
182+ handlerAdapterDef .getPropertyValues ().add ("webBindingInitializer" , bindingDef );
183+ handlerAdapterDef .getPropertyValues ().add ("messageConverters" , messageConverters );
172184 if (element .hasAttribute ("ignoreDefaultModelOnRedirect" )) {
173185 Boolean ignoreDefaultModel = Boolean .valueOf (element .getAttribute ("ignoreDefaultModelOnRedirect" ));
174- methodAdapterDef .getPropertyValues ().add ("ignoreDefaultModelOnRedirect" , ignoreDefaultModel );
186+ handlerAdapterDef .getPropertyValues ().add ("ignoreDefaultModelOnRedirect" , ignoreDefaultModel );
175187 }
176188 if (argumentResolvers != null ) {
177- methodAdapterDef .getPropertyValues ().add ("customArgumentResolvers" , argumentResolvers );
189+ handlerAdapterDef .getPropertyValues ().add ("customArgumentResolvers" , argumentResolvers );
178190 }
179191 if (returnValueHandlers != null ) {
180- methodAdapterDef .getPropertyValues ().add ("customReturnValueHandlers" , returnValueHandlers );
192+ handlerAdapterDef .getPropertyValues ().add ("customReturnValueHandlers" , returnValueHandlers );
181193 }
182- String methodAdapterName = parserContext .getReaderContext ().registerWithGeneratedName (methodAdapterDef );
194+ String handlerAdapterName = parserContext .getReaderContext ().registerWithGeneratedName (handlerAdapterDef );
183195
184196 RootBeanDefinition csInterceptorDef = new RootBeanDefinition (ConversionServiceExposingInterceptor .class );
185197 csInterceptorDef .setSource (source );
@@ -191,13 +203,14 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
191203 mappedCsInterceptorDef .getConstructorArgumentValues ().addIndexedArgumentValue (1 , csInterceptorDef );
192204 String mappedInterceptorName = parserContext .getReaderContext ().registerWithGeneratedName (mappedCsInterceptorDef );
193205
194- RootBeanDefinition methodExceptionResolver = new RootBeanDefinition (ExceptionHandlerExceptionResolver .class );
195- methodExceptionResolver .setSource (source );
196- methodExceptionResolver .setRole (BeanDefinition .ROLE_INFRASTRUCTURE );
197- methodExceptionResolver .getPropertyValues ().add ("messageConverters" , messageConverters );
198- methodExceptionResolver .getPropertyValues ().add ("order" , 0 );
206+ RootBeanDefinition exceptionHandlerExceptionResolver = new RootBeanDefinition (ExceptionHandlerExceptionResolver .class );
207+ exceptionHandlerExceptionResolver .setSource (source );
208+ exceptionHandlerExceptionResolver .setRole (BeanDefinition .ROLE_INFRASTRUCTURE );
209+ exceptionHandlerExceptionResolver .getPropertyValues ().add ("contentNegotiationManager" , contentNegotiationManager );
210+ exceptionHandlerExceptionResolver .getPropertyValues ().add ("messageConverters" , messageConverters );
211+ exceptionHandlerExceptionResolver .getPropertyValues ().add ("order" , 0 );
199212 String methodExceptionResolverName =
200- parserContext .getReaderContext ().registerWithGeneratedName (methodExceptionResolver );
213+ parserContext .getReaderContext ().registerWithGeneratedName (exceptionHandlerExceptionResolver );
201214
202215 RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition (ResponseStatusExceptionResolver .class );
203216 responseStatusExceptionResolver .setSource (source );
@@ -213,9 +226,9 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
213226 String defaultExceptionResolverName =
214227 parserContext .getReaderContext ().registerWithGeneratedName (defaultExceptionResolver );
215228
216- parserContext .registerComponent (new BeanComponentDefinition (methodMappingDef , methodMappingName ));
217- parserContext .registerComponent (new BeanComponentDefinition (methodAdapterDef , methodAdapterName ));
218- parserContext .registerComponent (new BeanComponentDefinition (methodExceptionResolver , methodExceptionResolverName ));
229+ parserContext .registerComponent (new BeanComponentDefinition (handlerMappingDef , methodMappingName ));
230+ parserContext .registerComponent (new BeanComponentDefinition (handlerAdapterDef , handlerAdapterName ));
231+ parserContext .registerComponent (new BeanComponentDefinition (exceptionHandlerExceptionResolver , methodExceptionResolverName ));
219232 parserContext .registerComponent (new BeanComponentDefinition (responseStatusExceptionResolver , responseStatusExceptionResolverName ));
220233 parserContext .registerComponent (new BeanComponentDefinition (defaultExceptionResolver , defaultExceptionResolverName ));
221234 parserContext .registerComponent (new BeanComponentDefinition (mappedCsInterceptorDef , mappedInterceptorName ));
@@ -261,6 +274,42 @@ else if (jsr303Present) {
261274 }
262275 }
263276
277+ private RuntimeBeanReference getContentNegotiationManager (Element element , Object source , ParserContext parserContext ) {
278+ RuntimeBeanReference contentNegotiationManagerRef ;
279+ if (element .hasAttribute ("content-negotiation-manager" )) {
280+ contentNegotiationManagerRef = new RuntimeBeanReference (element .getAttribute ("content-negotiation-manager" ));
281+ }
282+ else {
283+ RootBeanDefinition managerDef = new RootBeanDefinition (ContentNegotiationManager .class );
284+ managerDef .setSource (source );
285+ managerDef .setRole (BeanDefinition .ROLE_INFRASTRUCTURE );
286+ PathExtensionContentNegotiationStrategy strategy1 = new PathExtensionContentNegotiationStrategy (getDefaultMediaTypes ());
287+ HeaderContentNegotiationStrategy strategy2 = new HeaderContentNegotiationStrategy ();
288+ managerDef .getConstructorArgumentValues ().addIndexedArgumentValue (0 , Arrays .asList (strategy1 ,strategy2 ));
289+
290+ String beanName = "mvcContentNegotiationManager" ;
291+ parserContext .getReaderContext ().getRegistry ().registerBeanDefinition (beanName , managerDef );
292+ parserContext .registerComponent (new BeanComponentDefinition (managerDef , beanName ));
293+ contentNegotiationManagerRef = new RuntimeBeanReference (beanName );
294+ }
295+ return contentNegotiationManagerRef ;
296+ }
297+
298+ private Map <String , MediaType > getDefaultMediaTypes () {
299+ Map <String , MediaType > map = new HashMap <String , MediaType >();
300+ if (romePresent ) {
301+ map .put ("atom" , MediaType .APPLICATION_ATOM_XML );
302+ map .put ("rss" , MediaType .valueOf ("application/rss+xml" ));
303+ }
304+ if (jackson2Present || jacksonPresent ) {
305+ map .put ("json" , MediaType .APPLICATION_JSON );
306+ }
307+ if (jaxb2Present ) {
308+ map .put ("xml" , MediaType .APPLICATION_XML );
309+ }
310+ return map ;
311+ }
312+
264313 private RuntimeBeanReference getMessageCodesResolver (Element element , Object source , ParserContext parserContext ) {
265314 if (element .hasAttribute ("message-codes-resolver" )) {
266315 return new RuntimeBeanReference (element .getAttribute ("message-codes-resolver" ));
0 commit comments