CustomExceptionHandler not able to catch exceptions in spring boot - 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.

Related

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);
}
}

Exception handling for Spring Boot #Async methods

I'm pretty new to Spring Boot. In a project I'd like to send an email asyncronously. Below, you can see what I have so far.
A problem I have is the following: An external system sends a POST request to the controller. If some exception occurs while building or sending the mail, then the GlobalExceptionHandler does not get called. As a consequence, the controller always returns an HTTP 201, so the caller assumes that everything went fine.
How would I integrate my exception handlers with #ControllerAdvice in such async methods?
Controller
#PostMapping(value = "/mail", consumes = MediaType.APPLICATION_JSON_VALUE)
public void send(#Validated #RequestBody EmailNotificationRequest emailNotificationRequest) throws MessagingException {
emailService.sendMessage(emailNotificationRequest);
}
Service
#Async
public void sendMessage(EmailNotificationRequest emailNotificationRequest) throws MessagingException {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
// build the message
javaMailSender.send(mimeMessage);
}
ExceptionHandler
#RestControllerAdvice
#Slf4j
public class GlobalExceptionHandler extends AbstractExceptionHandler {
/**
* Handles any exception which is not handled by a specific {#link ExceptionHandler}.
*/
#ExceptionHandler(value = {Throwable.class})
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ApplicationResponse handleThrowable(Throwable ex) {
log.error("An unhandled error occurred: {}", ex.getMessage());
return buildErrorResponse();
}
}
How about moving the #Async into a lower level, so only the
javaMailSender.send(mimeMessage);
Will be called in an async way?
Extract it to a different bean with a public async method that wraps the javaMailSender and remove the Async from the mothod of sendMessage

How to test exceptions handling in #ControllerAdvice

I currently have two ControllerAdvice in my application, I'm supposed to merge them into one.
But I need to test them before and after the merge, test the exception and the object that the controller return me.
I'm trying to make a jUnit test with Mockito but it seems impossible to test the exceptions without any context, without a controller, etc ...
Does anyone know how can I proceed to achieve what I'm trying to do ?
I also try to throw manually an exception but obviously it wasn't catched by the ControllerAdvice.
So basically here is what i'm trying to do:
Manually throw an exception
This exception is handled by my ControllerAdvice
Check the returned object (code & message)
Here is a sample of code I have:
#Before
public void setup() {
...
mockMvc = MockMvcBuilders.standaloneSetup(getController())
.setControllerAdvice(new GlobalControllerExceptionHandler())
.setCustomArgumentResolvers(resolver, resolver_0, resolver_1)
.setHandlerExceptionResolvers(exceptionResolver).build();
}
#Controller
#RequestMapping("/tests")
public static class RestProcessingExceptionThrowingController {
#RequestMapping(value = "/exception", method = GET)
public #ResponseBody String find() {
throw new EntityNotFoundException();
}
}
#Test
public void testHandleException() throws Exception {
mockMvc.perform(get("/tests/exception"))
.andExpect(new ResultMatcher() {
#Override
public void match(MvcResult result) throws Exception {
result.getResponse().getContentAsString().contains("global_error_test");
}
})
.andExpect(status().isNotFound());
}
I have the good status code at the end but it doesn't use my ControllerAdvice (I try with the debugger)
You can just call handler method directly
#ControllerAdvice
MyAdvice{
#ExceptionHandeler(listOfExxcetpions)
public ResponseEntity someOfMyExceptionsHandler(Exception e){
.....
}
}
and in test
MuTest{
private MyAdvice advice=new MyAdvice();
#Test
public void oneOfTests(){
Exception e=new SomeSortOfExceptionToTest();
resp=advice.someOfMyExceptionsHandler(e)
assertThat(resp).....dostuff;
}
}
If you want to test how spring integrates with your handlers - if your annotations are correct, ordering serialization etc - well that will be an integration test and you have to boot up test context - then you can throw exceptions directly from controller methods.

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.

CXF - custom exception is not caught by CXF

I am developing a SOAP web service with CXF 2.3.3. I want to throw a custom exception when user has submitted wrong data. My exception class looks like this.
#WebFault(name="InvalidUserDataException", targetNamespace="http://foo.bar.com/")
#XmlAccessorType(XmlAccessType.FIELD)
public class InvalidUserDataException extends RuntimeException {
public InvalidUserDataException(){
super();
}
String validationErrors;
}
In my method Impl class I purposely throw this exception to see whether SoapFault exception is returned by CXF to client, but whatever I do to any of these classes results in same error: createNewUser has thrown exception, unwinding now.
Note that WSUserRegistration interface also declares itself that createNewUser method throws InvalidUserDataException.
public class WSUserRegistrationImpl implements WSUserRegistration {
#Autowired
IWSUserValidationProxy validationProxyImpl;
#Override
public int createNewUser(RegistrationInputProperty registrationInfo) throws InvalidUserDataException {
if (true) {
throw new InvalidUserDataException();
}
return 1;
}
}
My goal is to catch this exception from a SOAPFaultOutInterceptor and return a customized faultDetail.
How do I make CXF catch this error and return a SOAPFault object? Any ideas?
this would help you.
http://willemjiang.blogspot.com/2011/01/how-to-map-soap-fault-message-with.html

Resources