Closed
Description
MockMvc
created by MockMvcBuilders.standaloneSetup()
ignores @RestControllerAdvice
annotation attributes but works well for a @ControllerAdvice
/ResponseBody
pair.
- Spring Boot: 2.3.2
- Spring Framework: 5.2.8
Example: https://github.com/thecederick/MockMvc-ignores-RestControllerAdvice-annotation-fields
Failing Configuration
Controller:
@RestController
@RequestMapping
public class Api1Controller {
@PostMapping(value = "/endpoint1")
public String endpoint() {
return "done";
}
}
Controller advice:
@RestControllerAdvice(assignableTypes = Api1Controller.class)
@Order(Ordered.HIGHEST_PRECEDENCE)
public class Api1ControllerAdvice {
@ExceptionHandler(Throwable.class)
public String handleException(Throwable throwable) {
return this.getClass() + " - " + throwable.getClass();
}
}
Test:
@BeforeEach
public void setup() {
this.mockMvc = MockMvcBuilders
.standaloneSetup(controller)
.addDispatcherServletCustomizer(
dispatcherServlet -> dispatcherServlet.setThrowExceptionIfNoHandlerFound(true))
.setControllerAdvice(Api1ControllerAdvice.class, DefaultControllerAdvice.class)
.build();
}
@Test
void notFound() throws Exception {
mockMvc
.perform(
post("/test")
.contentType("application/json")
.content("{}"))
.andExpect(content().string(
"class com.example.demo.root.DefaultControllerAdvice - class org.springframework.web.servlet.NoHandlerFoundException"));
}
Working Configuration
@RestController
@RequestMapping
public class Api2Controller {
@PostMapping(value = "/endpoint2")
public String endpoint() {
return "done";
}
}
Controller advice:
@ControllerAdvice(assignableTypes = Api2Controller.class)
@ResponseBody
@Order(Ordered.HIGHEST_PRECEDENCE)
public class Api2ControllerAdvice {
@ExceptionHandler(Throwable.class)
public String handleException(Throwable throwable) {
return this.getClass() + " - " + throwable.getClass();
}
}
Test:
@BeforeEach
public void setup() {
this.mockMvc = MockMvcBuilders
.standaloneSetup(controller)
.addDispatcherServletCustomizer(
dispatcherServlet -> dispatcherServlet.setThrowExceptionIfNoHandlerFound(true))
.setControllerAdvice(
Api2ControllerAdvice.class,
DefaultControllerAdvice.class)
.build();
}
@Test
void notFound() throws Exception {
mockMvc
.perform(
post("/test")
.contentType("application/json")
.content("{}"))
.andExpect(content().string(
"class com.example.demo.root.DefaultControllerAdvice - class org.springframework.web.servlet.NoHandlerFoundException"));
}
Default advice
@RestControllerAdvice
@Order(Ordered.LOWEST_PRECEDENCE)
public class DefaultControllerAdvice {
@ExceptionHandler(Throwable.class)
public String handleException(Throwable throwable) {
return this.getClass() + " - " + throwable.getClass();
}
}
Summary
In the first configuration using the @RestControllerAdvice
annotation the test fails; with the second one, it passes as expected.