I have a custom Spring Boot AutoConfiguration
class in which I’m creating a @RequestScop
ed bean of a custom class - Foo
. In the same AutoConfiguration
class, I’m creating a bean of my global exception handler which is a @ControllerAdvice
. All these classes are a packaged as a jar and used as a dependency in my other Spring Boot web application. Whenever there’s an exception in a controller method, the appropriate exception handler is invoked in my global exception handler, except whenever there is an exception in Foo
, a BeanCreationException
is thrown and none of the global exception handlers get invoked. I tried adding @Order(Ordered.HIGHEST_PRECEDENCE)
as suggested in some SO answers, but none of them worked. Is it possible to handle such request scoped bean exceptions in the global exception handler - a @ControllerAdvice
? Much appreciated.
EDIT
This is my AutoConfiguration
class. (This is in a different jar)
@Configuration
@ConditionalOnClass({FooContext.class, MyGlobalExceptionHandler.class})
public class AutoConfiguration {
// This bean is used in a Controller
@Order
@RequestScope
@Bean
@ConditionalOnMissingBean(FooContext.class)
public FooContext fooContext() throws IOException {
// generateFooContext() throws the exception and Spring wraps it with BeanCreationException.
return FooContextFactory.generateFooContext();
}
@Bean
@ConditionalOnMissingBean
public MyGlobalExceptionHandler globalExceptionHandler(MyErrorHelper errorHelper) {
return new MyGlobalExceptionHandler (errorHelper);
}
}
This is MyGlobalExceptionHandler
(This is in a different jar)
@ControllerAdvice
@RefreshScope
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MyGlobalExceptionHandler {
// Never invoked
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> render(Exception ex) {
log.error("Exception occurred: ", ex);
return errorHelper.throwErrorException(DEFAULT_ERROR_CODE, HttpStatus.INTERNAL_SERVER_ERROR);
}
/// ...
}
I managed to solve it by registering an AbstractHandlerExceptionResolver
@Component
public class ResponseExceptionResolver extends AbstractHandlerExceptionResolver {
@SneakyThrows
@Override
protected ModelAndView doResolveException(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex
) {
return handleException(request, response);
}
private ModelAndView handleException(
HttpServletRequest request,
HttpServletResponse response
) {
response.setHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE);
ErrorResponse errorResponse = ...
return new ModelAndView(new MappingJackson2JsonView(), this.getErrorResponse(errorResponse));
}
private Map<String, String> getErrorResponse(ErrorResponse errorResponse) {
return new ObjectMapper().convertValue(errorResponse, new TypeReference<Map<String, String>>() {
});
}
}