My app is a Spring Boot web application. I'm having a unique problem catching my exception with my ExceptionHandler - I think it is because the exception is being thrown and rethrown multiple times in my app flow.
Here is a high level description of the problem:
I throw ExceptionType1 in my service.
My ExceptionType1 exception is caught by my ErrorController class's error() method
#Override
#RequestMapping
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
boolean isErr = (boolean) request.getAttribute("filter.error");
if (isErr) {
//the error was thrown by cta filter, throw ExceptionType2
throw new ExceptionType2(errorMsg, errorCode);
} else {
//handle other errors
I catch the error, convert the ExceptionType1 exception to ExceptionType2 exception and rethrow it as ExceptionType2
The ExceptionType2 exception thrown above is caught by my ExceptionHandler class
#Component
#ControllerAdvice
public class MyExceptionHandler {
#ExceptionHandler({ExceptionType2.class})
public final String handleExceptionType2(ExceptionType2 e) throws ExceptionType3 {
throw new ExceptionType3(errorMsg, errorCode);
}
The ExceptionHandler above has an #ExceptionHandler method that catches the ExceptionType2 error thrown in the previous step, converts this exception to ExceptionType3 and rethrows it.
5. Here's my problem. There is yet another ExceptionHandler class that is supposed to catch ExceptionType3 errors - but it is not working. I put a breakpoint in my #ExceptionHandler method for ExceptionType3 and it is never hit
TLDR -- I basically catch an exception in my code - then it is
converted to another exception type and
rethrown as the new exception type 3 times in my code.
It works the first 2 times but the last time I try to convert the exception and rethrow it as ExceptionType3 - it is not caught by my ExceptionHandler class for ExceptionType3.
My theory right now is - I have converted exception type and rethrown the exception too many times. Is there some limitation on this in Spring? The reason I think this is - if I create and throw ExceptionType3 at any point in the above steps before step 5 - it is able to be caught by the appropriate ExceptionHandler class.
Any advice on this would be appreciated.
I believe that Spring does not allow handling of exceptions re-thrown from other exception handlers. Exception handler is supposed to be a final point where exception should be converted to HTTP response or just logged.
One of the way (maybe a little dirty) to solve your issue is to call handler for ExceptionType3 manually.
Related
I've got a question about error handling in Spring.
There is #ExceptionHandler annotation for handling exceptions in controller. For example I need to handle invalid json and this will work:
#ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<Object> handleError(HttpServletRequest req, Exception ex) {
//Method logic
}
But! In this case if we throw HttpMessageNotReadableException inside rest method, then #ExceptionHandler will catch it anyway. So the question is: How can I handle only these exceptions which are thrown before we actually get into rest method?
When optimistic locking is enabled in Hibernate, Hibernate throws a runtime exception (HibernateOptimisticLockingFailureException).
When this exception is thrown we need to catch this exception and display a meaningful message to the user. (ex. "The object is modified by someone else.")
What I am thinking to do is catching this Runtime Exception in the service level and rethrow a custom checked exception like ConcurrentObjectModificationException.
Is this the correct approch to handle this?
I wrote an #ExceptionHandler to send the exception in JSON for REST requests. However, due to the way Spring Security works, AccessDeniedExceptions must not be handled.
If I simply rethrow an AccessDeniedException in the handler, I get an ERROR level logging saying:
Failed to invoke #ExceptionHandler method: SomeMethod() throws java.lang.Exception
org.springframework.security.access.AccessDeniedException: Access is denied
...Stack...
I cannot safely disable ERROR level logging for the class logging it (ExceptionHandlerExceptionResolver), but having these stacktrace is quite confusing for operations people.
Is there anyway to make #ExceptionHandler not handle this specific exception?
I think you could just use global exception handler instead, so you don't manually handle this AccessDeniedExceptions,
this global exception will be thrown for every kinds of exceptions (except for the exception handlers that you handle manually):
#ControllerAdvice
public class GlobalHandler {
#ExceptionHandler(Exception.class)
public ModelAndView handleException() {
return new ModelAndView("errorGlobal");
}
}
I have a web application in which I throw some custom exceptions(application exceptions annotated with #ApplicationException) and there is an exception mapper(provider annotated with #Provider) for each. Recently I forgot to annotate an exception with #ApplicationException and still the mapper is able to identify the exception and format the response properly.
Then I checked the documentation and I understood that the annotation will be inherited by its child class by default. So I removed the annotation from the super class and checked. The mapper still identified the exception and formatted the response.
Then I went even forward and tried throwing java.lang.IllegalArgumentException and wrote a mapper class for it. It also worked properly. Is javax.ws.rs.ext.ExceptionMapper independent of the exception being thrown. Will it not check if whether thrown exception is really annotated with #ApplicationException?
#Provider
public class IllegalArgumentExceptionMapper implements ExceptionMapper<java.lang.IllegalArgumentException> {
#Override
public Response toResponse(java.lang.IllegalArgumentException exception) {
return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build();
}
}
Somewhere in my service class:
throw new java.lang.IllegalArgumentException("Problem with the payload. Please check the payload you are sending");
The answer is no, it will not check if whether thrown exception is really annotated with #ApplicationException.
The exception mapper is independent of the #ApplicationException.
All the exception mapper knows is, if there's no exception caught until the almost last layer, it will be processed here, if it find a matching provider.
You can also actually create a provider for RuntimeException and all exception happened in the REST request will land here (but this is not good practice, we should always throw custom exception and catch them with the provider and convert them to good error response).
When you annotate the exception with #ApplicationException you can control things like whether the transaction should be rollback, and whether it will be wrapped by EJBException etc etc.
I'm writing a stand alone application, that has to start up and be left running unattended for long periods of time. Rather than have exceptions bring it to a halt, it needs to log the exception with enough information for the support people to have an idea what happened, and carry on.
As a result each exception is wrapped in a runtime exception, then thrown to be logged by a different part of the application. I'm using aop:config tags to create an aspect to log the runtime exceptions thrown by the rest of the application. The exception would then carry on up the call stack to an UncaughtExceptionHandler to end the exception silently.
However, the same exception is being caught repeatedly, and logged (each exception is written by a separate thread, and goes to a separate log file). In the debugger, both exceptions have the same ID.
My applicationContext is basic for this :
<aop:config>
<aop:aspect ref="exceptionLoggingAspect">
<aop:after-throwing method="logException"
pointcut="execution(* *.*(..))" throwing="exception" />
</aop:aspect>
</aop:config>
The UncaughtExceptionHandler is equally basic, at least till I get it working :
private void setUncaughtExceptionHandler()
{
final Handler handler = new Handler();
Thread.setDefaultUncaughtExceptionHandler(handler);
}
class Handler implements Thread.UncaughtExceptionHandler
{
#Override
public void uncaughtException(Thread t, Throwable e)
{
System.out.println("Throwable: " + e.getMessage());
System.out.println(t.toString());
}
}
I have experimented by restricting the pointcut to a single package, and throwing an exception from that package (not the package the exception logging is in), but it is still logged twice.
Is there something fundamentally wrong with this idea ? Advice appreciated.