A sample project demonstrating the issue can be found at: https://github.com/dirkbolte/javaexceptionhandlertest
I have a controller which is declared to produce JSON content:
@RestController
public class TestController {
@GetMapping(value = "exception", produces = MediaType.APPLICATION_JSON_VALUE)
public void test() {
}
}
The corresponding controller advice should map any exception to a BAD_REQUEST
:
@RestControllerAdvice
public class MyExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(value = Exception.class)
public void exceptionhandler() {
}
}
I test that a call with a wrong accept
header results in the correct error response code (as procudes
specifies something different):
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
class TestControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void test() throws Exception {
mockMvc.perform(
MockMvcRequestBuilders.get("/exception")
.accept(MediaType.APPLICATION_PDF)
).andExpect(status().isBadRequest());
}
}
The code above "fails successfully" :-) . In my production code I want to limit the controller advice to a certain controller (alternatively to a certain package), thus I specified assignableTypes
on @ControllerAdvice
: @RestControllerAdvice(assignableTypes = TestController.class)
. Now the test fails as the exception handler isn't called anymore. Same happens when specifying basePackages
or basePackageClasses
- or when using an interface.
The version on GitHub shows the test failure, so I hope it is easy to reproduce.
How can I use a ControllerAdvice explicitly for one or more Controller?
The requested URL will not get mapped to any Controller method here. This would result in a Status 406
error (due to the specified accept type). Since no exception is thrown from the Controller methods the ControllerAdvice would not be invoked.
On dispatcher level, org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#getExceptionHandlerMethod
will be called with handlerMethod = null
which is why only generic controller advices are applied.
The ControllerAdvice would work here, if the request contains additional metadata that the controller method is configured for and/or an exception is thrown from within that method.