Configuring Spring MVC

this section you’ll learn about two additional ways of configuring Spring MVC. Namely the MVC Java config and the MVC XML namespace.

The MVC Java config and the MVC namespace provide similar default configuration that overrides the DispatcherServlet defaults. The goal is to spare most applications from having to create the same configuration and also to provide higher-level constructs for configuring Spring MVC that serve as a simple starting point and require little or no prior knowledge of the underlying configuration.

You can choose either the MVC Java config or the MVC namespace depending on your preference. Also as you will see further below, with the MVC Java config it is easier to see the underlying configuration as well as to make fine-grained customizations directly to the created Spring MVC beans. But let’s start from the beginning.

Enabling the MVC Java Config or the MVC XML Namespace

To enable MVC Java config add the annotation @EnableWebMvc to one of your @Configuration classes:

@Configuration
@EnableWebMvc
public class WebConfig {

}

To achieve the same in XML use the mvc:annotation-driven element in your DispatcherServlet context (or in your root context if you have no DispatcherServlet context defined):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc.xsd">

	<mvc:annotation-driven/>

</beans>

The above registers a RequestMappingHandlerMapping, a RequestMappingHandlerAdapter, and an ExceptionHandlerExceptionResolver (among others) in support of processing requests with annotated controller methods using annotations such as @RequestMapping, @ExceptionHandler, and others.

It also enables the following:

  1. Spring 3 style type conversion through a ConversionService instance in addition to the JavaBeans PropertyEditors used for Data Binding.

  2. Support for formatting Number fields using the @NumberFormat annotation through the ConversionService.

  3. Support for formatting Date, Calendar, Long, and Joda Time fields using the @DateTimeFormat annotation.

  4. Support for validating @Controller inputs with @Valid, if a JSR-303 Provider is present on the classpath.

  5. HttpMessageConverter support for @RequestBody method parameters and @ResponseBody method return values from @RequestMapping or @ExceptionHandler methods.

    This is the complete list of HttpMessageConverters set up by mvc:annotation-driven:

    1. ByteArrayHttpMessageConverter converts byte arrays.

    2. StringHttpMessageConverter converts strings.

    3. ResourceHttpMessageConverter converts to/from org.springframework.core.io.Resource for all media types.

    4. SourceHttpMessageConverter converts to/from a javax.xml.transform.Source.

    5. FormHttpMessageConverter converts form data to/from a MultiValueMap<String, String>.

    6. Jaxb2RootElementHttpMessageConverter converts Java objects to/from XML — added if JAXB2 is present and Jackson 2 XML extension is not present on the classpath.

    7. MappingJackson2HttpMessageConverter converts to/from JSON — added if Jackson 2 is present on the classpath.

    8. MappingJackson2XmlHttpMessageConverter converts to/from XML — added if Jackson 2 XML extension is present on the classpath.

    9. AtomFeedHttpMessageConverter converts Atom feeds — added if Rome is present on the classpath.

    10. RssChannelHttpMessageConverter converts RSS feeds — added if Rome is present on the classpath.

See Message Converters for more information about how to customize these default converters.

Note

Jackson JSON and XML converters are created using ObjectMapper instances created by {api-spring-framework}/http/converter/json/Jackson2ObjectMapperBuilder.html[Jackson2ObjectMapperBuilder] in order to provide a better default configuration.

This builder customizes Jackson’s default properties with the following ones:

It also automatically registers the following well-known modules if they are detected on the classpath:

  1. jackson-datatype-jdk7: support for Java 7 types like java.nio.file.Path.

  2. jackson-datatype-joda: support for Joda-Time types.

  3. jackson-datatype-jsr310: support for Java 8 Date & Time API types.

  4. jackson-datatype-jdk8: support for other Java 8 types like Optional.

Customizing the Provided Configuration

To customize the default configuration in Java you simply implement the WebMvcConfigurer interface or more likely extend the class WebMvcConfigurerAdapter and override the methods you need:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	// Override configuration methods...

}

To customize the default configuration of <mvc:annotation-driven/> check what attributes and sub-elements it supports. You can view the Spring MVC XML schema or use the code completion feature of your IDE to discover what attributes and sub-elements are available.

Conversion and Formatting

By default formatters for Number and Date types are installed, including support for the @NumberFormat and @DateTimeFormat annotations. Full support for the Joda Time formatting library is also installed if Joda Time is present on the classpath. To register custom formatters and converters, override the addFormatters method:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void addFormatters(FormatterRegistry registry) {
		// Add formatters and/or converters
	}

}

In the MVC namespace the same defaults apply when <mvc:annotation-driven> is added. To register custom formatters and converters simply supply a ConversionService:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc.xsd">

	<mvc:annotation-driven conversion-service="conversionService"/>

	<bean id="conversionService"
			class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
		<property name="converters">
			<set>
				<bean class="org.example.MyConverter"/>
			</set>
		</property>
		<property name="formatters">
			<set>
				<bean class="org.example.MyFormatter"/>
				<bean class="org.example.MyAnnotationFormatterFactory"/>
			</set>
		</property>
		<property name="formatterRegistrars">
			<set>
				<bean class="org.example.MyFormatterRegistrar"/>
			</set>
		</property>
	</bean>

</beans>
Note

See [format-FormatterRegistrar-SPI] and the FormattingConversionServiceFactoryBean for more information on when to use FormatterRegistrars.

Validation

Spring provides a Validator interface that can be used for validation in all layers of an application. In Spring MVC you can configure it for use as a global Validator instance, to be used whenever an @Valid or @Validated controller method argument is encountered, and/or as a local Validator within a controller through an @InitBinder method. Global and local validator instances can be combined to provide composite validation.

Spring also supports JSR-303/JSR-349 Bean Validation via LocalValidatorFactoryBean which adapts the Spring org.springframework.validation.Validator interface to the Bean Validation javax.validation.Validator contract. This class can be plugged into Spring MVC as a global validator as described next.

By default use of @EnableWebMvc or <mvc:annotation-driven> automatically registers Bean Validation support in Spring MVC through the LocalValidatorFactoryBean when a Bean Validation provider such as Hibernate Validator is detected on the classpath.

Note

Sometimes it’s convenient to have a LocalValidatorFactoryBean injected into a controller or another class. The easiest way to do that is to declare your own @Bean and also mark it with @Primary in order to avoid a conflict with the one provided with the MVC Java config.

If you prefer to use the one from the MVC Java config, you’ll need to override the mvcValidator method from WebMvcConfigurationSupport and declare the method to explicitly return LocalValidatorFactory rather than Validator. See Advanced Customizations with MVC Java Config for information on how to switch to extend the provided configuration.

Alternatively you can configure your own global Validator instance:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public Validator getValidator(); {
		// return "global" validator
	}

}

and in XML:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc.xsd">

	<mvc:annotation-driven validator="globalValidator"/>

</beans>

To combine global with local validation, simply add one or more local validator(s):

@Controller
public class MyController {

	@InitBinder
	protected void initBinder(WebDataBinder binder) {
		binder.addValidators(new FooValidator());
	}

}

With this minimal configuration any time an @Valid or @Validated method argument is encountered, it will be validated by the configured validators. Any validation violations will automatically be exposed as errors in the BindingResult accessible as a method argument and also renderable in Spring MVC HTML views.

Interceptors

You can configure HandlerInterceptors or WebRequestInterceptors to be applied to all incoming requests or restricted to specific URL path patterns.

An example of registering interceptors in Java:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(new LocaleInterceptor());
		registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
		registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
	}

}

And in XML use the <mvc:interceptors> element:

<mvc:interceptors>
	<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
	<mvc:interceptor>
		<mvc:mapping path="/**"/>
		<mvc:exclude-mapping path="/admin/**"/>
		<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
	</mvc:interceptor>
	<mvc:interceptor>
		<mvc:mapping path="/secure/*"/>
		<bean class="org.example.SecurityInterceptor"/>
	</mvc:interceptor>
</mvc:interceptors>

Content Negotiation

You can configure how Spring MVC determines the requested media types from the request. The available options are to check the URL path for a file extension, check the "Accept" header, a specific query parameter, or to fall back on a default content type when nothing is requested. By default the path extension in the request URI is checked first and the "Accept" header is checked second.

The MVC Java config and the MVC namespace register json, xml, rss, atom by default if corresponding dependencies are on the classpath. Additional path extension-to-media type mappings may also be registered explicitly and that also has the effect of whitelisting them as safe extensions for the purpose of RFD attack detection (see [mvc-ann-requestmapping-rfd] for more detail).

Below is an example of customizing content negotiation options through the MVC Java config:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
		configurer.mediaType("json", MediaType.APPLICATION_JSON);
	}
}

In the MVC namespace, the <mvc:annotation-driven> element has a content-negotiation-manager attribute, which expects a ContentNegotiationManager that in turn can be created with a ContentNegotiationManagerFactoryBean:

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
	<property name="mediaTypes">
		<value>
			json=application/json
			xml=application/xml
		</value>
	</property>
</bean>

If not using the MVC Java config or the MVC namespace, you’ll need to create an instance of ContentNegotiationManager and use it to configure RequestMappingHandlerMapping for request mapping purposes, and RequestMappingHandlerAdapter and ExceptionHandlerExceptionResolver for content negotiation purposes.

Note that ContentNegotiatingViewResolver now can also be configured with a ContentNegotiationManager, so you can use one shared instance throughout Spring MVC.

In more advanced cases, it may be useful to configure multiple ContentNegotiationManager instances that in turn may contain custom ContentNegotiationStrategy implementations. For example you could configure ExceptionHandlerExceptionResolver with a ContentNegotiationManager that always resolves the requested media type to "application/json". Or you may want to plug a custom strategy that has some logic to select a default content type (e.g. either XML or JSON) if no content types were requested.

View Controllers

This is a shortcut for defining a ParameterizableViewController that immediately forwards to a view when invoked. Use it in static cases when there is no Java controller logic to execute before the view generates the response.

An example of forwarding a request for "/" to a view called "home" in Java:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		registry.addViewController("/").setViewName("home");
	}

}

And the same in XML use the <mvc:view-controller> element:

<mvc:view-controller path="/" view-name="home"/>

View Resolvers

The MVC config simplifies the registration of view resolvers.

The following is a Java config example that configures content negotiation view resolution using FreeMarker HTML templates and Jackson as a default View for JSON rendering:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.enableContentNegotiation(new MappingJackson2JsonView());
		registry.jsp();
	}

}

And the same in XML:

<mvc:view-resolvers>
	<mvc:content-negotiation>
		<mvc:default-views>
			<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
		</mvc:default-views>
	</mvc:content-negotiation>
	<mvc:jsp/>
</mvc:view-resolvers>

Note however that FreeMarker, Tiles, Groovy Markup and script templates also require configuration of the underlying view technology.

The MVC namespace provides dedicated elements. For example with FreeMarker:

<mvc:view-resolvers>
	<mvc:content-negotiation>
		<mvc:default-views>
			<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
		</mvc:default-views>
	</mvc:content-negotiation>
	<mvc:freemarker cache="false"/>
</mvc:view-resolvers>

<mvc:freemarker-configurer>
	<mvc:template-loader-path location="/freemarker"/>
</mvc:freemarker-configurer>

In Java config simply add the respective "Configurer" bean:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.enableContentNegotiation(new MappingJackson2JsonView());
		registry.freeMarker().cache(false);
	}

	@Bean
	public FreeMarkerConfigurer freeMarkerConfigurer() {
		FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
		configurer.setTemplateLoaderPath("/WEB-INF/");
		return configurer;
	}

}

Serving of Resources

This option allows static resource requests following a particular URL pattern to be served by a ResourceHttpRequestHandler from any of a list of Resource locations. This provides a convenient way to serve static resources from locations other than the web application root, including locations on the classpath. The cache-period property may be used to set far future expiration headers (1 year is the recommendation of optimization tools such as Page Speed and YSlow) so that they will be more efficiently utilized by the client. The handler also properly evaluates the Last-Modified header (if present) so that a 304 status code will be returned as appropriate, avoiding unnecessary overhead for resources that are already cached by the client. For example, to serve resource requests with a URL pattern of /resources/** from a public-resources directory within the web application root you would use:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/");
	}

}

And the same in XML:

<mvc:resources mapping="/resources/**" location="/public-resources/"/>

To serve these resources with a 1-year future expiration to ensure maximum use of the browser cache and a reduction in HTTP requests made by the browser:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/").setCachePeriod(31556926);
	}

}

And in XML:

<mvc:resources mapping="/resources/**" location="/public-resources/" cache-period="31556926"/>

The mapping attribute must be an Ant pattern that can be used by SimpleUrlHandlerMapping, and the location attribute must specify one or more valid resource directory locations. Multiple resource locations may be specified using a comma-separated list of values. The locations specified will be checked in the specified order for the presence of the resource for any given request. For example, to enable the serving of resources from both the web application root and from a known path of /META-INF/public-web-resources/ in any jar on the classpath use:

@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/resources/**")
				.addResourceLocations("/", "classpath:/META-INF/public-web-resources/");
	}

}

And in XML:

<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/public-web-resources/"/>

When serving resources that may change when a new version of the application is deployed it is recommended that you incorporate a version string into the mapping pattern used to request the resources so that you may force clients to request the newly deployed version of your application’s resources. Support for versioned URLs is built into the framework and can be enabled by configuring a resource chain on the resource handler. The chain consists of one more ResourceResolver instances followed by one or more ResourceTransformer instances. Together they can provide arbitrary resolution and transformation of resources.

The built-in VersionResourceResolver can be configured with different strategies. For example a FixedVersionStrategy can use a property, a date, or other as the version. A ContentVersionStrategy uses an MD5 hash computed from the content of the resource (known as "fingerprinting" URLs). Note that the VersionResourceResolver will automatically use the resolved version strings as HTTP ETag header values when serving resources.

ContentVersionStrategy is a good default choice to use except in cases where it cannot be used (e.g. with JavaScript module loaders). You can configure different version strategies against different patterns as shown below. Keep in mind also that computing content-based versions is expensive and therefore resource chain caching should be enabled in production.

Java config example;

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/resources/**")
				.addResourceLocations("/public-resources/")
				.resourceChain(true).addResolver(
					new VersionResourceResolver().addContentVersionStrategy("/**"));
	}

}

XML example:

<mvc:resources mapping="/resources/**" location="/public-resources/">
	<mvc:resource-chain>
		<mvc:resource-cache/>
		<mvc:resolvers>
			<mvc:version-resolver>
				<mvc:content-version-strategy patterns="/**"/>
			</mvc:version-resolver>
		</mvc:resolvers>
	</mvc:resource-chain>
</mvc:resources>

In order for the above to work the application must also render URLs with versions. The easiest way to do that is to configure the ResourceUrlEncodingFilter which wraps the response and overrides its encodeURL method. This will work in JSPs, FreeMarker, and any other view technology that calls the response encodeURL method. Alternatively, an application can also inject and use directly the ResourceUrlProvider bean, which is automatically declared with the MVC Java config and the MVC namespace.

Webjars are also supported with WebJarsResourceResolver, which is automatically registered when the "org.webjars:webjars-locator" library is on classpath. This resolver allows the resource chain to resolve version agnostic libraries from HTTP GET requests "GET /jquery/jquery.min.js" will return resource "/jquery/1.2.0/jquery.min.js". It also works by rewriting resource URLs in templates <script src="/jquery/jquery.min.js"/> → <script src="/jquery/1.2.0/jquery.min.js"/>.

Falling Back On the "Default" Servlet To Serve Resources

This allows for mapping the DispatcherServlet to "/" (thus overriding the mapping of the container’s default Servlet), while still allowing static resource requests to be handled by the container’s default Servlet. It configures a DefaultServletHttpRequestHandler with a URL mapping of "/**" and the lowest priority relative to other URL mappings.

This handler will forward all requests to the default Servlet. Therefore it is important that it remains last in the order of all other URL HandlerMappings. That will be the case if you use <mvc:annotation-driven> or alternatively if you are setting up your own customized HandlerMapping instance be sure to set its order property to a value lower than that of the DefaultServletHttpRequestHandler, which is Integer.MAX_VALUE.

To enable the feature using the default setup use:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}

}

Or in XML:

<mvc:default-servlet-handler/>

The caveat to overriding the "/" Servlet mapping is that the RequestDispatcher for the default Servlet must be retrieved by name rather than by path. The DefaultServletHttpRequestHandler will attempt to auto-detect the default Servlet for the container at startup time, using a list of known names for most of the major Servlet containers (including Tomcat, Jetty, GlassFish, JBoss, Resin, WebLogic, and WebSphere). If the default Servlet has been custom configured with a different name, or if a different Servlet container is being used where the default Servlet name is unknown, then the default Servlet’s name must be explicitly provided as in the following example:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		configurer.enable("myCustomDefaultServlet");
	}

}

Or in XML:

<mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/>

Path Matching

This allows customizing various settings related to URL mapping and path matching. For details on the individual options check out the {api-spring-framework}/web/servlet/config/annotation/PathMatchConfigurer.html[PathMatchConfigurer] API.

Below is an example in Java config:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void configurePathMatch(PathMatchConfigurer configurer) {
		configurer
		    .setUseSuffixPatternMatch(true)
		    .setUseTrailingSlashMatch(false)
		    .setUseRegisteredSuffixPatternMatch(true)
		    .setPathMatcher(antPathMatcher())
		    .setUrlPathHelper(urlPathHelper());
	}

	@Bean
	public UrlPathHelper urlPathHelper() {
	    //...
	}

	@Bean
	public PathMatcher antPathMatcher() {
	    //...
	}

}

And the same in XML, use the <mvc:path-matching> element:

<mvc:annotation-driven>
    <mvc:path-matching
        suffix-pattern="true"
        trailing-slash="false"
        registered-suffixes-only="true"
        path-helper="pathHelper"
        path-matcher="pathMatcher"/>
</mvc:annotation-driven>

<bean id="pathHelper" class="org.example.app.MyPathHelper"/>
<bean id="pathMatcher" class="org.example.app.MyPathMatcher"/>

Message Converters

Customization of HttpMessageConverter can be achieved in Java config by overriding {api-spring-framework}/web/servlet/config/annotation/WebMvcConfigurerAdapter.html#configureMessageConverters-java.util.List-[configureMessageConverters()] if you want to replace the default converters created by Spring MVC, or by overriding {api-spring-framework}/web/servlet/config/annotation/WebMvcConfigurerAdapter.html#extendMessageConverters-java.util.List-[extendMessageConverters()] if you just want to customize them or add additional converters to the default ones.

Below is an example that adds Jackson JSON and XML converters with a customized ObjectMapper instead of default ones:

@Configuration
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {

	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
				.indentOutput(true)
				.dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
				.modulesToInstall(new ParameterNamesModule());
		converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
		converters.add(new MappingJackson2XmlHttpMessageConverter(builder.xml().build()));
	}

}

In this example, Jackson2ObjectMapperBuilder is used to create a common configuration for both MappingJackson2HttpMessageConverter and MappingJackson2XmlHttpMessageConverter with indentation enabled, a customized date format and the registration of jackson-module-parameter-names that adds support for accessing parameter names (feature added in Java 8).

Note

Enabling indentation with Jackson XML support requires woodstox-core-asl dependency in addition to jackson-dataformat-xml one.

Other interesting Jackson modules are available:

  1. jackson-datatype-money: support for javax.money types (unofficial module)

  2. jackson-datatype-hibernate: support for Hibernate specific types and properties (including lazy-loading aspects)

It is also possible to do the same in XML:

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper" ref="objectMapper"/>
        </bean>
        <bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter">
            <property name="objectMapper" ref="xmlMapper"/>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

<bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
      p:indentOutput="true"
      p:simpleDateFormat="yyyy-MM-dd"
      p:modulesToInstall="com.fasterxml.jackson.module.paramnames.ParameterNamesModule"/>

<bean id="xmlMapper" parent="objectMapper" p:createXmlMapper="true"/>

Advanced Customizations with MVC Java Config

As you can see from the above examples, MVC Java config and the MVC namespace provide higher level constructs that do not require deep knowledge of the underlying beans created for you. Instead it helps you to focus on your application needs. However, at some point you may need more fine-grained control or you may simply wish to understand the underlying configuration.

The first step towards more fine-grained control is to see the underlying beans created for you. In MVC Java config you can see the javadocs and the @Bean methods in WebMvcConfigurationSupport. The configuration in this class is automatically imported through the @EnableWebMvc annotation. In fact if you open @EnableWebMvc you can see the @Import statement.

The next step towards more fine-grained control is to customize a property on one of the beans created in WebMvcConfigurationSupport or perhaps to provide your own instance. This requires two things — remove the @EnableWebMvc annotation in order to prevent the import and then extend from DelegatingWebMvcConfiguration, a subclass of WebMvcConfigurationSupport. Here is an example:

@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {

	@Override
	public void addInterceptors(InterceptorRegistry registry){
		// ...
	}

	@Override
	@Bean
	public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
		// Create or let "super" create the adapter
		// Then customize one of its properties
	}

}
Note

An application should have only one configuration extending DelegatingWebMvcConfiguration or a single @EnableWebMvc annotated class, since they both register the same underlying beans.

Modifying beans in this way does not prevent you from using any of the higher-level constructs shown earlier in this section. WebMvcConfigurerAdapter subclasses and WebMvcConfigurer implementations are still being used.

Advanced Customizations with the MVC Namespace

Fine-grained control over the configuration created for you is a bit harder with the MVC namespace.

If you do need to do that, rather than replicating the configuration it provides, consider configuring a BeanPostProcessor that detects the bean you want to customize by type and then modifying its properties as necessary. For example:

@Component
public class MyPostProcessor implements BeanPostProcessor {

	public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
		if (bean instanceof RequestMappingHandlerAdapter) {
			// Modify properties of the adapter
		}
	}

}

Note that MyPostProcessor needs to be included in an <component scan/> in order for it to be detected or if you prefer you can declare it explicitly with an XML bean declaration.

results matching ""

    No results matching ""