javaspringspring-bootspring-mvccontroller-advice

Spring Boot 404 : no handler found exception in Controller Advice isn't catched


So I am trying to send a customized answer when user is trying to call an url unknown to my application. To do that I first added to my application.properties (in both main and test folders)

spring.mvc.throw-exception-if-no-handler-found=true
spring.web.resources.add-mappings=false

So that if no handler is found an exception is thrown. This exception should be of type NoHandlerFoundException

Then I added in my controller advice a custom exception handler my controller advice (simplified)

@EnableWebMvc // (I tried with and without it doesn't change the error)
@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE) // (I tried with and without it doesn't change the error)
public class ExceptionsHandler extends ResponseEntityExceptionHandler {
    // invalid route handler
    @Override
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ResponseBody
    protected ResponseEntity<Object> handleNoHandlerFoundException(
    NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        String error = "No handler found for " + ex.getHttpMethod() + " " + ex.getRequestURL();

        ApiError apiError = new ApiError(HttpStatus.NOT_FOUND, ex.getLocalizedMessage(), error);
        return new ResponseEntity<>(apiError.getErrors(), new HttpHeaders(), apiError.getStatus());
    }
}

Using this, when calling an unknown url in my test using :

this.mvc.perform(get("/ttt"))
        .andDo(print())
        .andExpect(status().isNotFound())
        .andExpect(content().contentType(MediaType.APPLICATION_JSON))
        .andExpect(jsonPath("$.error").value("No Handler found for GET /ttt"));

I get in my debug console : o.s.web.servlet.PageNotFound : No mapping for GET /ttt Though, answer doesn't have my custom error message as I also get in my debug console :

MockHttpServletResponse:
           Status = 404
    Error message = null
          Headers = []
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

I then tried

    @ExceptionHandler({NoHandlerFoundException.class})
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ResponseBody
    public ResponseEntity<Object> handleNoHandler(HttpServletRequest request, Exception ex) {
        String error = ex.getMessage();
        return new ResponseEntity<>(error, new HttpHeaders(), HttpStatus.NOT_FOUND);
    }

But then a Illegal state exception : Failed to load application context is thrown with cause

IllegalStateException:Ambiguous @ExceptionHandler method mapped for [class org.framework.web.servlet.NoHandlerFoundException]

ALso, When I put breakpoints in my handlers and debug my test, the execution never stops at any breakpoint.


Solution

  • So it seems that MockMvc has trouble with building MockHttpServletRequest when using exception handlers thus the empty content. When I run my springboot application and try calling an unknown url in my navigator, It works. I have the expected error 404; with body : No handler found using the override method.

    see more here, stack accepted answer with 100+ usefulness score -> Unit test MockHttpServletRequest not returning content type