ControllerAdvice not triggering for specific exceptions - spring

I have #RestControllerAdvice (spring boot 1.4.2) that looks like this
#RestControllerAdvice
public class GlobalControllerExceptionHandler {
#ExceptionHandler(value = { AvailabilityException.class })
public RestResponse availabilityException(AvailabilityException ex) {
//logic
}
#ExceptionHandler(value = { HrsException.class })
public RestResponse hrsException(HrsException ex) {
//logic
}
}
This class catches excpetions of type HrsException but does not catch exceptions of type AvailabilityException
HrsException
public class HrsException extends RuntimeException {
public Integer errorCode;
public String messageKey;
}
AvailabilityException
public class AvailabilityException extends HrsException {
}
So I'm guessing AvailabilityException is not being caught by the controller advice because it's extending HrsException, what's the explanation for this and how can I continue with this a design?
Basically I want to create a bunch of exceptions that inherits from HrsException (because I don't want duplicate code) and want to catch them in the controller advice.

There was a catch somewhere in the code that was interfering with the controller advice, if someone faces the issue make sure you have no catches in your code preventing the chain from reaching the controller advice.

Related

Request validation with quarkus

I have a REST Enspoint
...
#GET
public Response read (#Valid Param parameters) {
}
...
How can I catch this Exception to handle this in Quarkus?
Is there a special Exceptionhandler available?
You can handle the exception by using:
#Provider
public class MyViolationExceptionMapper implements ExceptionMapper<ValidationException> {
#Override
public Response toResponse(ValidationException exception) {
// do something
}
}
You can draw inspiration for how to handle things by looking at the built-in exception mapper.

How to handle exception in controller method with controlleradvice being in place

I do have a Spring boot controller class and a corresponding ControllerAdvice class which has ExceptionHandlers to handle different exception.
My controller method calls a simple validation helper class to validate input fields which throws an exception if validation fails. Now if I don't put a try catch block in my controller it keeps complaining me that you have a method which has untangled exception even through the logic for handling validation exception is defined in controlleradvice class. Please suggest how do I solve it.
From the method of ValidationHelper class if you throw any Checked Exception then you need to use a try-catch block to call that method.
If you don't want then it's better to use any Custom Exception class which will extend the RuntimeException class and you throw that exception. Then you don't need to explicitly mention the throws as well as you don't need to have a try-catch block at the controller.
#RestController
#RequiredArgsConstructor
public class SampleController {
private final ValidationHelper validationHelper;
#ResponseStatus(HttpStatus.OK)
#GetMapping("/sample")
public String getRequest(#RequestParam String name) {
validationHelper.validate(name);
return "";
}
}
#Service
public class ValidationHelper {
public Boolean validate(String name) {
throw new CustomException("Validation Failed");
}
}
public class CustomException extends RuntimeException {
public CustomException(String message) {
super(message);
}
}

CustomExceptionHandler not able to catch exceptions in spring boot

In my spring boot application, I have created a custom exception handler using #ControllerAdvice, and a custom exception ServerException, when I throw the custom exception, it does not get caught by my customExcpetionHandler, though I am able to check whether actually the excpetion is thrown and it is getting thrown as shown by logs.
Below is the code for my ServerException:
public class ServerException extends Exception {
/**
*
*/
private static final long serialVersionUID = <uid>;
public ServerException(String message) {
super(message);
}
}
Below is my GlobalCustomExceptionHandler class:
#ControllerAdvice
#EnableWebMvc
public class GlobalCustomExceptionHandler extends ResponseEntityExceptionHandler{
#ExceptionHandler(ServerException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public ModelMap handleServerException(ServerException ex) {
ModelMap modelMap = new ModelMap();
modelMap.addAttribute("status", "ERROR_400_Bad_Request");
modelMap.addAttribute("error_message", ex.getMessage());
return modelMap;
}
}
I am throwing the exception in one of the restcontroller as follows:
throw new ServerException("invalid server configs");
But I can only see the exception getting printed in log file, and not getting it as response mentioned in handleServerException() method of GlobalCustomExceptionHandler class.
What could be the reason ?
I have just reproduced Your copy-pasted piece of code with simple REST endpoint, and it works as expected:
#RestController
public class SystemController {
#GetMapping(value = "/system")
public ResponseEntity<Object> getSystem() throws ServerException {
if (true)
throw new ServerException("Checking this out");
return new ResponseEntity<>(HttpStatus.OK);
}
}
Calling http://localhost:8080/system
Results with:
{"status":"ERROR_400_Bad_Request","error_message":"Checking this out"}
I need bigger picture to help You. Paste controller that is throwing that as well as main application config class.

Adding Global Error Handling for Spring Rest Controllers

I have many controllers like this one
#RestController
#RequestMapping("/contracts")
public class ContractsController {
#Autowired
ContractsService service;
#PostMapping("/selectAll")
public WebMessageModel selectAll(#RequestBody ContractFiltersInputModel inputModel) {
return new WebMessageModel(true, service.selectAll(inputModel));
}
}
And I have another controller
#Controller
public class BaseController {
private static Logger logger = LoggerFactory.getLogger(IndexController.class);
#RequestMapping
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
String requestURI = request.getRequestURI();
StringBuffer requestURL = request.getRequestURL();
logger.info("-----requestURI => " + requestURI + ", requestURL => " + requestURL);
request.getRequestDispatcher(requestURI).forward(request, response);
logger.info("-----response has been commited");
} catch (Throwable t) {
t.printStackTrace();
request.getRequestDispatcher("/handleException").forward(request, response);
}
}
}
I need all incoming requests to go through this BaseController in order to make one global TRY-CATCH block. How can I implement that? Is this approach really good idea? Maybe there are some other awesome aproaches?
If you want to intercept every request to your controllers endpoint before it enters the controller method, you would need to implement a filter. You may go through this tutorial to understand how to implement a filter.
If you want to catch all the exceptions that result out of requests to your controller endpoints (the exception could have been thrown anywhere - controller, service, repository etc) at one place, then you should implement ExceptionHandlers within a ControllerAdvice. A simple example would be like this:
#ControllerAdvice
public class ExceptionHandlerAdvice {
#ExceptionHandler(MismatchedInputException.class)
public ResponseEntity<Void> handleMismatchedInputException(MismatchedInputException e) {
return ResponseEntity.status(BAD_REQUEST).build();
}
#ExceptionHandler(InvalidFormatException.class)
public ResponseEntity<Void> handleInvalidFormatException(InvalidFormatException e) {
return ResponseEntity.status(UNPROCESSABLE_ENTITY).build();
}
}
The above will make sure any exception that's specified in the exception handler will be caught here so that exception response from your REST API can be streamlined. More on the same here.
You can use filters to execute some logic before or after requests. In your case a global error handling would be more helpful:
#ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(value = { IllegalArgumentException.class, IllegalStateException.class })
protected ResponseEntity<Object> handleConflict(
RuntimeException ex, WebRequest request) {
String bodyOfResponse = "This should be application specific";
return handleExceptionInternal(ex, bodyOfResponse,
new HttpHeaders(), HttpStatus.CONFLICT, request);
}
}
This snippet is taken from here.
What you looking for is #ControllerAdvice. Here's how to use it http://blog.codeleak.pl/2013/11/controlleradvice-improvements-in-spring.html

Does ControllerAdvice increase response time?

Is there any speed difference when using ControllerAdvice throwing RuntimeException, and when manually returning ResponseEntity to handle client errors?
1) ControllerAdvice
#RestController
public class ObjectController {
#PostMapping
public Object save(#RequestBody Object object) {
if (service.isInvalid(object))
throw new ObjectException("Client error");
return service.save(object);
}
}
public class ObjectException extends RuntimeException {
}
#ControllerAdvice
public class ObjectControllerAdvice extends ResponseEntityExceptionHandler {
#ExceptionHandler(value = {ObjectException.class})
protected ResponseEntity<Object> handleConflict(ObjectException ex, WebRequest request) {
return handleExceptionInternal(ex, ex.getLocalizedMessage(), new HttpHeaders(),
HttpStatus.BAD_REQUEST, request);
}
}
2) Manually returning ResponseEntity
#RestController
public class ObjectController {
#PostMapping
public ResponseEntity<Object> save(#RequestBody Object object) {
if (service.isInvalid(object))
return new ResponseEntity<>("Client error", HttpStatus.BAD_REQUEST);
return new ResponseEntity<Object>(service.save(object), HttpStatus.OK);
}
}
I imagine the difference is response time is negligible with the second approach possibly being very slightly faster. But the real advantage of having a #ControllerAdvice class with #ExceptionHandlers is that these can be used for multiple endpoints over multiple #Controllers and you won't have to repeat the code everywhere.
No, it's not that much different. And I think using the #ControllerAdvice is a best practice when you would like to handle your Custom Exception or to centralize the Exception to a Global class. There is a simple sample in this answer: Error page registrar and Global exception handling
Hope this help.

Resources