Custom exception not caught in calling method [duplicate] - java

This question already has answers here:
Spring Async Uncaught Exception handler
(4 answers)
Closed 3 years ago.
I have a custom exception that I throw in a class that is not caught in another class.
I don't know what's wrong here :
Class MailService.java
#Async
public void sendMail(String to, String subject) throws EmailNotSentException {
throw new EmailNotSentException();
}
Class MailResource.java
#RequestMapping(value = "/mails-envoyes",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<MailEnvoye> createMailEnvoye(#RequestBody MailEnvoye mailEnvoye, HttpServletRequest request) throws URISyntaxException {
try{
mailService.sendMail(to, "subject");
}catch (EmailNotSentException e){
log.debug(e.getLocalizedMessage());
}
}
Exception
public class EmailNotSentException extends MessagingException {
public EmailNotSentException() {
super();
}
public EmailNotSentException(String message) {
super(message);
}
public EmailNotSentException(String message, Exception e) {
super(message, e);
}
}

The issue is probably the #Async annotation (I'm assuming this code runs with Spring) ... as it says on the tin, it run it asynchronously, which means that it will run in a different thread, so the calling method will never receive the Exception.
If you want to handle the exception in the way you have in your code, just remove the #Async annotation.
There are a few articles around which explain how to catch an exception from an async method (google is your friend), and make it available so something else can deal with it, but it's always asynchronously.

Related

Is throws declaration in feign client useless without defined error decoder?

I have a feign client like this
#FeignClient(name = "client")
public interface SomeClient {
#RequestLine("GET /?q={q}")
void execute(URI baseUrl, #Param("q") String q) throws SomeExceptionInMyCode;
}
Looking to this throws SomeExceptionInMyCode I'm asking myself when this exception will be thrown. There is no configuration for client defined, no error decoder. Exception looks like this.
public class SomeExceptionInMyCode extends Exception{
private final int statusCode;
private final String reason;
private final String body;
// getters and setters
}
Will there be an automatic attempt to decode HTTP response to this exception in case of failure? Or throws SomeExceptionInMyCode is useless and can be removed without any impact.
I searched inside my code and this exception is never created.
Will there be an automatic attempt to decode http response to this exception in case of failure?
Nope, it doesn't work like this and the SomeExceptionMyCode will not be thrown. The throws clause is useless. Even if the endpoint throws this exception from its implementation, it will be wrapped as a cause of FeignException.
The correct way to handle feign client exceptions is using Custom exception handling implementing ErrorDecoder:
public class StashErrorDecoder implements ErrorDecoder {
#Override
public Exception decode(String methodKey, Response response) {
if (response.status() >= 400 && response.status() <= 499) {
// return 4XX exception
}
if (response.status() >= 500 && response.status() <= 599) {
// return 5XX exception
}
}
}
At this point you can perform the custom exception creation and rethrowing.
An alternative solution is to use Spring-alike #RestControllerAdvice:
#RestControllerAdvice
public class ExceptionHandler {
#ExceptionHandler(FeignException.class)
public String handleFeignStatusException(FeignException e, HttpServletResponse response) {
// ...
}
}
What if the StashErrorDecoder throws a checked exception? That is allowed. In this case the throws clause in the interface surely helps. This way you can catch and handle the exception thrown by Feign. At least it should work this way.

#Async will not call by #ControllerAdvice for global exception

I have a service class with #Async method and If it's calling method throwing any exception then the #ControllerAdvice will not call for global exception handling. But for other classes and services it will call advice and sending email properly.
#Service
public class FileScanServiceImpl implements FileScanService {
#Override
#Async
public void scanFileScheduler() throws MQException {
try{
messageProducer.putFileNameToMQ(fileName);
} catch (Exception e) {
ExceptionUtility.handleException(e, currentFile);
}
}
The ExceptionUtility is used for checking instance on exception and doing some functionality there and throwing custom exception.
public static void handleException(Exception e throws MQException {
String errMsg = "";
if (e instanceof MQException) {
// some functionality
throw new MQException(subject, errMsg);
}
}
And this is my #ControlleAdvice
#ControllerAdvice
public class GlobalExceptionHandler {
#ExceptionHandler(MQException.class)
#ResponseBody
public void handleMQException(HttpServletRequest request, MQException ex) {
// send email
}
}
It there any solution for #Async which will call #ControllerAdvice for global exception, also the existing functionality will not break.
#ExceptionHandler was created to catch only "synchronous exceptions". If it had the ability to catch exceptions from asynchronous threads, then when several threads start and if any of them fail, the request to the server would be interrupted completely and the system could remain in an inconsistent state (due to many other active threads generated by this request)
For handling asynchronous exceptions Spring has the AsyncUncaughtExceptionHandler interface:
public class YourAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
#Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
// Your exception handling logic
}
}
More information can be found here in the Exceptions section: https://www.baeldung.com/spring-async

Exception Handling in JAX-RS

java 8, spring, rest
I am trying to capture the Response that comes from exception mapper, and do something with it in the caller which throws the exception. Thanks.
#Provider
public class CustomerExceptionHandler implements ExceptionMapper<CustomerException>
{
#Override
public Response toResponse(CustomerException exception)
{
return Response.status(Status.BAD_REQUEST).entity(CustomerException.getMessage()).build();
}
}
public class CustomerException extends Exception implements Serializable
{
private static final long serialVersionUID = 1L;
public CustomerException() {
super();
}
public CustomerException(String msg) {
super(msg);
}
public CustomerException(String msg, Exception e) {
super(msg, e);
}
}
public class ExceptionDemo{
public void getExceptionResponse(){
//do something
throw new CustomerException("Something is wrong");// CustomerExceptionHandler is going to return me a Response, how can I capture the response here?
//capture response and do something with it
}
}
I'm not sure ExceptionMappers work in the way you think they do.
When some code in the endpoint throws an exception, and this exception percolates all the way out of the endpoint and back into the container itself (Spring in this case), then the registered ExceptionMappers are consulted to see if they match the thrown exception, and the relevant one's public Response toResponse(T e) {} method is called to transform it into a Response.
The ExceptionMapper doen't get called as part of your endpoint code, and you won't be able to take action based on its resultant Response because it hasn't yet been called. You just need to throw the exception out of the endpoint.

Custom Exception is not handled with #ExceptionHandler annotated method

I have a custom exception class defined as
public class CustomAuthenticationException extends RuntimeException{
}
From a controller method I am throwing this exception as below
#RequestMapping(value="/tasks", method=RequestMethod.GET)
public String loadTasks(HttpServletRequest request){
try
{
if (!isAuthenticatedRequest(request))
{
throw new CustomAuthenticationException();
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
return "tasks/tasks";
}
To catch this exception from that controller's scope, I have defined a method with #ExceptionHandler annotation as below
#ExceptionHandler(CustomAuthenticationException.class)
public void handleCustomException(CustomAuthenticationException ex){
//method is not getting invoked
}
When I initiate the GET request and expect the exception to be handled by the aformentioned method, I get only the error stack trace in the console. The exception handler method is never invoked.
But, with other defined exceptions like MethodArgumentNotValidException, the handler methods are invoked correctly. For example I got the following exception handler working:
#ExceptionHandler(MethodArgumentNotValidException.class)
#ResponseBody
public ErrorResponseHolder handleFieldValidationError(MethodArgumentNotValidException ex, HttpServletResponse response){
//method got invoked. do something with the exception
}
How can I resolve the issue with the custom exceptions ?
Handling of the exception is not proper, in a method loadTasks you are throwing the exception and catching the exception hence it is not propagating.
If you wanted to handle unhanded exceptions, for example generic exceptions (Exception.class) you need to write a method that should handle all these exception in common exception handling class.
#ExceptionHandler(Exception.class)
public void handleUnhandledException(Exception ex){
// handle the exception here
}
Once you are throwing the exception never ever catch the exception in same method, catch the exception where you are sending the proper response.

Jersey Custom Exception Not Caught in Servlet Class?

I am using Below Custom Exception class in my project
public class BadRequestException extends WebApplicationException {
private static final long serialVersionUID = 1L;
private String message;
public BadRequestException(String message) {
super();
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
I have created a Mapper class also..
public class BadRequestExceptionMapper implements ExceptionMapper<BadRequestException> {
public Response toResponse(BadRequestException brexec) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(brexec.getResponse().getEntity()).type(MediaType.APPLICATION_JSON).build();
}
}
I am calling my service through a Servlet and the Exception is thrown by one of its method but i am not able to catch it in Servlet class.I have used below code to catch the exception..
try{
//Some Business logic then
service.path("restful").path("jwbservice/" + methodName + "/" + id).header("lid", lid).delete(String.class);
}
catch (BadRequestException ex) {
out.println(ex);
}
catch(Exception exe){
out.println(exe);
}
And the service method i have used this code in my Service class which will throw the exception.
#DELETE
#Path("/deleteLink/{id}")
#Produces(MediaType.APPLICATION_JSON)
public String deleteLink(#PathParam("id") int id, #HeaderParam("lid") String lid) throws BadRequestException {
if (id<= 0) {
throw new BadRequestException("Required Parameter: id");
}
//Some Business Logic
}
My Service throw the BadRequestException but in Servlet it is going to Exception catch not in BadRequestException Catch block.
Can any one know what i am doing wrong.
You will never get that exception in your servlet. This is because the servlet is effectively a REST client, and you are invoking a remote resource method to get some data. The resource call will either be successful (and some data will be mapped back), or it will fail and you will get no data (or a client side error).
On a side note, there is a problem in your server side exception mapper. You do not verify that the exception actually has a response entity before calling:
brexec.getResponse().getEntity()
In cases where the exception doesn't have a response the above code will cause a null pointer exception.
Some quick notes:
Exception classes already have a message property. You do not need to define an additional one
Your exception mapper needs to check for a non-existent response property, before trying to do something with it
The resource path in your servlet does not appear to match the server side path. I assume that is a copy/paste error.

Categories