Spring Boot, @EnableWebMvc And Common Use-Cases

It turns out that Spring Boot doesn’t mix well with the standard Spring MVC @EnableWebMvc. What happens when you add the annotation is that spring boot autoconfiguration is disabled.

The bad part (that wasted me a few hours) is that in no guide you can find that explicitly stated. In this guide it says that Spring Boot adds it automatically, but doesn’t say what happens if you follow your previous experience and just put the annotation.

In fact, people that are having issues stemming from this automatically disabled autoconfiguration, are trying to address it in various ways. Most often – by keeping @EnableWebMvc, but also extending Spring Boot’s WebMvcAutoConfiguration. Like here, here and somewhat here. I found them after I got the idea and implemented it that way. Then realized doing it is redundant, after going through Spring Boot’s code and seeing that an inner class in the autoconfiguration class has a single-line javadoc stating

Configuration equivalent to {@code @EnableWebMvc}.

That answered my question whether spring boot autoconfiguration misses some of the EnableWebMvc “features”. And it’s good that they extended the class that provides EnableWebMvc, rather than mirroring the functionality (which is obvious, I guess).

What should you do when you want to customize your beans? As usual, extend WebMvcConfigurerAdapter (annotate the new class with @Component) and do your customizations.

So, bottom line of the particular problem: don’t use @EnableWebMvc in spring boot, just include spring-web as a maven/gradle dependency and it will be autoconfigured.

The bigger picture here resulted in me adding a comment in the main configuration class detailing why @EnableWebMvc should not be put there. So the autoconfiguration magic saved me doing a lot of stuff, but I still added a line explaining why something isn’t there.

And that’s because of the common use-cases – people are used to using @EnableWebMvc. So the most natural and common thing to do is to add it, especially if you don’t know how spring boot autoconfiguration works in detail. And they will keep doing it, and wasting a few hours before realizing they should remove it (or before extending a bunch of boot’s classes in order to achieve the same effect).

My suggestion in situations like this is: log a warning. And require explicitly disabling autoconfiguration in order to get rid of the warning. I had to turn on debug to see what gets autoconfigured, and then explore a bunch of classes to check the necessary conditions in order to figure out the situation.

And one of Spring Boot’s main use-cases is jar-packaged web applications. That’s what most tutorials are for, and that’s what it’s mostly used for, I guess. So there should be special treatment for this common use case – with additional logging and logged information helping people get through the maze of autoconfiguration.

I don’t want to be seen as “lecturing” the Spring team, who have done amazing job in having good documentation and straightforward behaviour. But in this case, where multiple sub-projects “collide”, it seems it could be improved.

8 thoughts on “Spring Boot, @EnableWebMvc And Common Use-Cases”

  1. A few years ago I went through exactly the same path as you. And made the same conclusions.

    When I say “exactly” I mean: I also add comment to my web configuration explaining why adding @EnableWebMvc here would be error. 🙂

    And what is really bad in this situation, is the fact, that you can encounter the problem, which is not even related to this annotation at all from point of view of a person, who does not know all the implementation details.

    Several years ago I spent many hours trying to solve a problem, that spring-boot ignores Jackson configuration from my application.properties file.

    The LocalDateTime fields serializing as arrays instead of ISO-8601 strings.

    The documentation say, that `spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false` should work. All examples in the internet say it should work, even source code of java8 jackson serializers (which should be enabled by default according to spring-boot’s documentation) say it should work, but it doesn’t!

    I don’t remember how I understood that @EnableWebMvc was the problem. And this is only because I’m very pedantic person and wanted to solve the problem, not workaround it. But many people in my place would have done differently. Just declare new ObjectMapper bean adding custom serializers here and disabling much of spring-boot’s (a great product for a spring application, I should say) cool features.

    I think, many newcomers face this problem sooner or later, so spring-boot should explicitly say “You enabled @EnableWebMvc annotatiton! Are you crazy?! Disable it asap!”. Preferably in big red letters. 🙂

  2. I’m finding I do not like Spring Boot’s approach to MVC configuration. If you have done anything non-default with your ApplicationContext, you cannot get it to throw an exception for “No Handler Found”. Which breaks your overall exception handling. Also, you cannot (successfully) override the “mvcContentNegotiationManager()” bean to fix Spring’s exception handling (it refuses to send a content type that is not Accept’ed by client, to the point of masking important errors).

    However, if I use the Spring MVC style of configuration, I can easily get my REST services working correctly, but I can’t get it to serve up static content any more (simple HTML for HAL UI, for example). Spring Boot has gone its own way wrt static content and has buried the static content configuration too deeply to be re-used. At least, I haven’t figured out how, yet.

    Spring Boot is great for prototyping. But it’s just too loose and over-opinionated for production use. Unfortunately, I see no clean migration path to a production-ready configuration.

  3. Nice write up. I was following a Spring tutorial (but using Springboot) and @EnablewebMvc had me tripped up for sometime.

  4. If you don’t use @EnableWebMvc annotation you might not initially notice any difference but things like content-type and accept header, generally content negotiation won’t work.

Leave a Reply

Your email address will not be published. Required fields are marked *