16

I need to extend the WebMvcConfigurationSupport class too modify two things:

@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
    @Override
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
        handlerMapping.setRemoveSemicolonContent(false);
        handlerMapping.setOrder(1);
        return handlerMapping;
    }
}

I like the defaults that are registered from the WebMvcAutoConfiguration class but due to the conditional annotation on the class, when I extend the WebMvcConfigurationSupport class it prevents the auto configuration from happening.

@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
    WebMvcConfigurerAdapter.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@Order(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter(DispatcherServletAutoConfiguration.class)
public class WebMvcAutoConfiguration {...}

Is there to have the WebMvcAutoConfiguration class load without having to essentially copy/paste most of the code in that class?

Or is it possible to call RequestMappingHandlerMapping setOrder() and setRemoveSemicolonContent() from somewhere else so I can just use the @EnableWebMvc annotation and have the autoconfiguration class run without any issues?

Thanks in advance!

Cory Comer
  • 165
  • 1
  • 2
  • 7

4 Answers4

13

Extend from DelegatingWebMvcConfiguration instead of WebMvcConfigurationSupport, it will not prevent the autoconfig to take place:

@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {
    @Override
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
        handlerMapping.setRemoveSemicolonContent(false);
        handlerMapping.setOrder(1);
        return handlerMapping;
    }
}
padilo
  • 996
  • 9
  • 18
9

I managed to customize the RequestMappingHandlerMapping while keeping WebMvcAutoConfiguration using a BeanPostProcessor:

@Configuration
public class RequestMappingConfiguration {
    @Bean
    public RequestMappingHandlerMappingPostProcessor requestMappingHandlerMappingPostProcessor() {
        return new RequestMappingHandlerMappingPostProcessor();
    }

    public static class RequestMappingHandlerMappingPostProcessor implements BeanPostProcessor {

        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof RequestMappingHandlerMapping) {
                ((RequestMappingHandlerMapping) bean).setUseSuffixPatternMatch(false);
            }
            return bean;
        }

        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    }
}

I would be happy if Spring Boot provides a better way to handle that... maybe something could be done around PathMatchConfigurer ?

Romain F.
  • 766
  • 10
  • 15
  • 2
    I have found that this solution works in the case where there is SpringFox Swagger Docket defined in the application . The solution above using the DelegatingWebMvcConfiguration causes the swagger doc display to fail . – diarmuid Feb 04 '17 at 11:06
  • 1
    Nice solution. But could you not just directly declare `RequestMappingHandlerMappingPostProcessor` as `@Configuration` here ? – Victor Petit Nov 22 '17 at 16:58
7

Your analysis is correct (@EnableWebMvc or directly extending WebMvcConfigurationSupport will switch off the WebMvcAutoConfiguration). I'm not sure what the alternative is, since a) we need a "get-out" clause for the autoconfig, and b) I don't think Spring likes to have two WebMvcConfigurationSupports in the same context. Happy to discuss on github if you want to try and find a way to change it (there might be some middle ground).

Dave Syer
  • 56,583
  • 10
  • 155
  • 143
  • Thanks for the quick reply Dave! I'm still a bit green with Spring Boot (Spring in general tbh) ... I started down the road of just creating a new SimpleUrlHandlerMapping bean since I noticed the DispatchServlet grabs all the beans of type HandlerMapping, but I got a little turned around creating the ResourceHttpRequestHandler, and put things down for a bit. I'll see if I can find something a little less hacky and either throw it here or on Github, maybe an easier way of injecting and ordering the HandlerMapping beans, I'll have to poke at it for a bit. Thanks! – Cory Comer Mar 08 '14 at 11:38
  • For your specific narrow use case here I think it would suffice to add a `@Bean` of type `RequestMappingHandlerMapping` (copying the code from `WebMvcConfigurationSupport`). You would need it to have a lower order than the default one (which begs the question: why you use order=1 in your custom mapping?). – Dave Syer Mar 08 '14 at 16:14
  • I've been challenging myself on that question as well. My use case involves mapping undetermined requests to a "catch-all" ant-style mapping, e.g., /** The intent was that any mapping with a higher specificity would be mapped first, which is the case for annotated controllers, but is not the case for resource handlers. The goal was to push the resource handlers down a level of precedence below the annotated controllers without losing the /** style mapping. I've been playing with the @Bean idea for the handler mapping actually, so I think that's the right way to go, thanks! – Cory Comer Mar 09 '14 at 21:28
0

I think the best way to do this in Spring Boot now is to add a WebMvcRegistrations component to your context - this solution didn't exist at the time of your question (it's been available since Spring Boot 1.4.0).

ryanp
  • 4,905
  • 1
  • 30
  • 39
  • this is still very limited in case of Exception Handlers as it allows to override only ExceptionHandlerExceptionResolver, the one we are interested are the default ones added after. – Aubergine Apr 12 '19 at 23:35