Controller Advice bean not instantiated at proper order in Spring Boot 2.4

56
April 17, 2021, at 10:40 AM

I'm implementing an global exception handling using ControllerAdvice and have trouble having it working with Spring Boot 2.4.

I have a class SecurityExceptionTranslater that is annotated with @ControllerAdvice and implements ExceptionTranslater where ExceptionTranslater is an custom interface.

SecurityExceptionTranslater is an managed bean introduced in my @Configuration configuration

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication
@AutoConfigureAfter(SecurityAutoConfiguration.class)
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
public class SecurityAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean(ExceptionTranslater.class)
    public ExceptionTranslater exceptionTranslater() {
        return new SecurityExceptionTranslater();
    }
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http, SecurityWebSupport support) throws Exception {
        return http.exceptionHandling()
                .authenticationEntryPoint(support)
                .accessDeniedHandler(support)
                .and()
                .build();
    }
    @Bean
    public SecurityWebSupport securityProblemSupport(
            @Qualifier("handlerExceptionResolver") HandlerExceptionResolver handlerExceptionResolver) {
        return new SecurityWebSupport(handlerExceptionResolver);
    }
}

SecurityWebSupport is used to take over exception handling thrown by Spring Security.

public class SecurityWebSupport implements AuthenticationEntryPoint, AccessDeniedHandler {
    private final HandlerExceptionResolver resolver;
    public SecurityWebSupport(final HandlerExceptionResolver resolver) {
        this.resolver = resolver;
    }
    @Override
    public void commence(final HttpServletRequest request, final HttpServletResponse response,
                         final AuthenticationException exception) {
        resolver.resolveException(request, response, null, exception);
    }
    @Override
    public void handle(final HttpServletRequest request, final HttpServletResponse response,
                       final AccessDeniedException exception) {
        resolver.resolveException(request, response, null, exception);
    }
}

As far as I have been inspecting into Spring Boot, exceptionTranslater bean is always created after creation of handlerExceptionResolver defined in WebMvcConfigurationSupport, where Controller beans are collected and manipulated. For that exceptionTranslater has not been instantiated yet and ExceptionTranslater neither is annotated with @ControllerAdive nor contains any @ExceptionHandler annotated method, exceptionTranslater is ignored by handlerExceptionResolver.

However, the configuration works if

  1. Spring Boot is downgraded to 2.3
  2. or SecurityWebSupport bean is removed
  3. or return type of @Bean method exceptionTranslater is modified as concrete type SecurityExceptionTranslater

By doing 1. and 2., exceptionTranslater bean is created before handlerExceptionResolver.

By doing 3., exceptionTranslater is still created after handlerExceptionResolver but it will be proper registered because of @ControllerAdvice annotation and @ExceptionHanlder method.

I'm looking forward to an explanation and a solution.

Thanks all in advance.

Answer 1

I was closer to the answer. After another few hours digging into it, I finally find out the cause.

The root cause is @AutoConfigureAfter(SecurityAutoConfiguration.class).

SecurityAutoConfiguration depends on SecurityFilterChain and in my configuration, my custom SecurityAutoConfiguration depends on SecurityWebSupport, which depends on HandlerExceptionResolver. This is why my ExceptionTranslater is always instantiated before HandlerExceptionResolver.

I ignored the annotation while I was adapting my code to work with Spring Boot 2.4.

READ ALSO
What should I enter to the connection string to connect my NodeJS application to a MongoDB server?

What should I enter to the connection string to connect my NodeJS application to a MongoDB server?

I am trying to connect to a MongoDB to a nodejsI have the MongoDB running and I have an ENV file with a connection string variable

33
How to achieve accordion functionality in this?

How to achieve accordion functionality in this?

I am trying to achieve bootstrap accordion like functionality in this code, what I want is one collapse should hide when other one opensI am using bootstrap 3

60
How to save the frames of video on Local Disk?

How to save the frames of video on Local Disk?

I am extracting frames from video , it is extracting and displaying all the frames on canvas means on the web browserI am trying to save that frame on disk using local-storage

22