I am facing two issues when I'm using DelegatingWebMvcConfiguration in my custom autoconfiguration module:

  1. Creating a configuration class that simply extends DelegatingWebMvcConfiguration does not work, because methods like extendHandlerExceptionResolvers are not called. The same method is called, when WebMvcConfigurer is implemented instead. Why is this the case?

  2. As a workaround, I wrote the following configuration class:

@Configuration
@EnableWebMvc
public class ExampleConfiguration extends DelegatingWebMvcConfiguration {

  @Configuration
  public class Inner implements WebMvcConfigurer {

      @Override
      public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        //Calls methods like ExampleConfiguration.this.mvcContentNegotiationManager() that are unavailable in WebMvcConfigurer
      }
  }

  @Bean
  public Dummy dummy() {
    return new Dummy();
  }

  protected static final class Dummy {

  }
}

If the Dummy bean does not exist (or is unused), I'm getting the following error:

The dependencies of some of the beans in the application context form a cycle:

   documentationPluginsBootstrapper defined in URL [jar:file:/.../maven/repository/io/springfox/springfox-spring-web/2.9.2/springfox-spring-web-2.9.2.jar!/springfox/documentation/spring/web/plugins/DocumentationPluginsBootstrapper.class]
      ↓
   webMvcRequestHandlerProvider defined in URL [jar:file:/.../maven/repository/io/springfox/springfox-spring-web/2.9.2/springfox-spring-web-2.9.2.jar!/springfox/documentation/spring/web/plugins/WebMvcRequestHandlerProvider.class]
      ↓
   org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration
┌─────┐
|  com.example.configuration.ExampleConfiguration $Inner
↑     ↓
|  com.example.configuration.ExampleConfiguration 
└─────┘

Both of these things look like a bug to me, but I am not experienced enough with Spring to be sure.

Comment From: wilkinsona

Thanks for the report. It's extendHandlerExceptionResolvers on DelegatingWebMvcConfiguration that calls the corresponding method on the configurers. If the configurers are being called then extendHandlerExceptionResolvers must be getting called on an instance of DelegatingWebMvcConfiguration.

I suspect that you may have two instances of DelegatingWebMvcConfiguration. The presence of org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration in the error suggests that this is the case. This could be due to auto-configuration ordering. I think it would happen if Boot's WebMvcAutoConfiguration runs before your custom auto-configuration.

That's about all that I can infer from what you have shared thus far. If the above doesn't help and you would like us to spend some more time investigating, please take the time to provide a complete and minimal example that reproduces the problem.

Comment From: Jobarion

I've created a minimal example: - Autoconfiguration: https://github.com/Jobarion/bug-demo-spring-autoconfiguration - Application: https://github.com/Jobarion/bug-demo-spring

Another observation I've had is that the name of the configuration class matters. Maybe it's some local quirk, but if I rename class, I always get the cycle error

Comment From: wilkinsona

Thanks for the sample. When I run it I can see that method1 is not being called. I have also been able to confirm some of my guesses.

There are indeed two DelegatingWebMvcConfiguration beans. I modified the main method to look like the following:

public static void main(String[] args) {
    ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
    Map<String, DelegatingWebMvcConfiguration> mvcConfigurations = context.getBeansOfType(DelegatingWebMvcConfiguration.class);
    System.out.println(mvcConfigurations);
}

And it output the following:

{org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration=org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration@2b9b7f1f, com.example.configuration.MvcConfiguration=com.example.configuration.MvcConfiguration$$EnhancerBySpringCGLIB$$c0c4c9ef@264c5d07}

There's no ordering on com.example.configuration.MvcConfiguration so it's running after WebMvcAutoConfiguration and duplicating some of the beans that it creates. If you want to replace Spring Boot's MVC auto-configuration with your own, you should use @AutoConfigureBefore(WebMvcAutoConfiguration.class) on MvcConfiguration. With this change in place, I then see a failure:

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

┌─────┐
|  com.example.configuration.MvcConfiguration$Inner
↑     ↓
|  com.example.configuration.MvcConfiguration
└─────┘

This circular dependency exists because MvcConfiguration requires all WebMvcConfigurer beans when it is being created and, because it's not static, Inner requires an MvcConfiguration instance to create it so there's a cycle. I think Inner was an attempt at working around the problem so it can probably just be removed. If I do that combined with the ordering change above, method2 is then called as expected.

Another observation I've had is that the name of the configuration class matters. Maybe it's some local quirk, but if I rename class, I always get the cycle error

In the absence of any ordering on an auto-configuration class, alphabetical ordering is used. This ensures that the order remains stable and isn't affected by changes to the ordering of the classpath and the like.