I'm using Spring MVC with Spring Boot and Thymeleaf. I have normal controllers that return the name of a Thymeleaf template and REST controllers annotated with @RepsonseBody.
Let's say I have an EntityNotFoundException that is thrown by some code that is called by the controller. If it is thrown, I want to return a 404 status code and an error page or error message for REST controllers respectively.
My current setup for normal controllers:
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
@Controller
public class FooController {
@RequestMapping("/foo") public String foo() {
try {
...
} catch (EntityNotFoundException enfe) {
throw new ResourceNotFoundException(enfe.getMessage());
}
return "foo";
}
}
For REST cotrollers I don't catch the exception and let a global exception handler pick it up:
@Controller
public class BarController {
@RequestMapping("/bar")
@ResponseBody
public SomeDto bar() throws EntityNotFoundException {
...
return someDto;
}
}
@ControllerAdvice
public class ExceptionHandlerAdvice {
@ExceptionHandler(EntityNotFoundException.class)
public final ResponseEntity<Object> handleEntityNotFoundExceptionEntityNotFoundException enfe) {
return new ResponseEntity<>(enfe.getMessage, HttpStatus.NOT_FOUND);
}
}
I don't want to catch and rethrow in my normal controllers as well. The global handler should handle both:
@ExceptionHandler(EntityNotFoundException.class)
public final Object handleEntityNotFoundException(EntityNotFoundException enfe) {
if (/* is REST controller? */) {
return new ResponseEntity<>(enfe.getMessage(), HttpStatus.NOT_FOUND);
} else {
Map<String, Object> model = ImmutableMap.of("message", enfe.getMessage());
return new ModelAndView("error", model, HttpStatus.NOT_FOUND);
}
}
Is there a way to determine where the exception came from, i.e. if the controller is annotated with @ResponseBody ore something alike?
I found a solution. You can inject the current controller method as a HandlerMethod parameter.
@ExceptionHandler(EntityNotFoundException.class)
public final Object handleEntityNotFoundException(EntityNotFoundException enfe, HandlerMethod handlerMethod) {
boolean isRestController = handlerMethod.hasMethodAnnotation(ResponseBody.class)
|| handlerMethod.getBeanType().isAnnotationPresent(ResponseBody.class)
|| handlerMethod.getBeanType().isAnnotationPresent(RestController.class);
if (isRestController) {
return new ResponseEntity<>(enfe.getMessage(), HttpStatus.NOT_FOUND);
} else {
Map<String, Object> model = ImmutableMap.of("message", enfe.getMessage());
return new ModelAndView("error", model, HttpStatus.NOT_FOUND);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With