Stacktrace of custom exception is not printed in Spring Boot 2.3 - java

Error stacktrace is not printed in console for the custom exception that is annotated with #ResponseStatus
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public class InternalErrorException extends RuntimeException {
public InternalErrorException(String message) {
super(message);
}
public InternalErrorException(String message, Throwable throwable) {
super(message, throwable);
}
}
Throwing exception like throw new InternalErrorException("error", e), never get the stacktrace printed in the console unlesss I remove the annotation #ResponseStatus
How could I get it printed while keeping the annotation #ResponseStatus?

See Annotation Type ResponseStatus API doc.
Warning: when using this annotation on an exception class, or when setting the reason attribute of this annotation, the HttpServletResponse.sendError method will be used.
With HttpServletResponse.sendError, the response is considered complete and should not be written to any further. Furthermore, the Servlet container will typically write an HTML error page therefore making the use of a reason unsuitable for REST APIs. For such cases it is preferable to use a ResponseEntity as a return type and avoid the use of #ResponseStatus altogether.
HttpServletResponse.sendError does not throw your error and I guess it is never logged because of that.
Maybe you want to implement exception handler for that exception to get it logged.
Related question

Related

ExceptionHandler doesn't catch HandlerInterceptor exception if endpoint path is unknown

I have a component that implements the HandlerInterceptor interface, and implements the preHandle method. In this method I retrieve a parameter from the request, and throw an IllegalArgumentException if that parameter is missing.
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String parameter = request.getHeader("parameter123");
if (StringUtils.isEmpty(parameter)) {
throw new IllegalArgumentException("parameter123 not specified");
}
[...]
return true;
}
In another class annotated with #ControllerAdvice, I have a ExceptionHandler that catches the IllegalArgumentExceptions and turns those into a formatted response with HTTP status code 400.
When this is executed by triggering a valid path of my API, everything works just fine. Problems arise when I try to call an invalid/unexisting path of my API. The HandlerInterceptor is called and the exception is thrown but my ExceptionHandler is not triggered and the result is a basic HTTP status code 500 exception. It seems to both override the basic HTTP status 404 mechanism, while also preventing the triggering of my ExceptionHandlers (even an ExceptionHandler on Exception.class doesn't ever get called).
Any explanations regarding this behaviour are welcome ! Thanks
Although this may be an old question, I want to provide an answer for anyone who may come across it in the future.
When you raise an exception in the preHandle method of a HandlerInterceptor, it may be wrapped in another exception called NestedServletException. This is a specific exception thrown by the Spring framework.
It's worth noting that NestedServletException is a runtime exception that occurs when a servlet or filter throws an exception. It encloses the original exception and provides additional information about the location where the exception occurred.

Why is the stackTrace not printed when extending the ResponseEntityExceptionHandler in Spring?

I'm building a spring boot application. I'm trying to use a decent way of handling rest responses when an exceptions is raised. So I extended the ResponseEntityExceptionHandler into a class named RestResponseEntityExceptionHandler.
The problem is that when an exception is thrown, the stackTrace is not printed in the console. when I delete this RestResponseEntityExceptionHandler class, the stacktrace is printed again in the console !
Here is what the RestResponseEntityExceptionHandler class looks like :
#RestControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(value = { IllegalArgumentException.class, TechnicalException.class})
protected void handleBadRequest(RuntimeException e, HttpServletResponse response) throws IOException
{
response.sendError(HttpStatus.BAD_REQUEST.value(), e.getMessage());
}
}
I am using logback for logging.
I found some tricks to deal with that, like adding a logger.error("Details : ", exception); which works fine and prints the stackTrace but I prefer not to use a solution like that since it works only for the exceptions handeled by that class... the other exceptions wont print the stackTrace.
Any explanations why the stackTrace is not printed ?
Thanx in advance.
Because You are handling Exception. If you want to print along with the handling, put logger inside ExceptionHandler methods.
It is not "printed" because you are already handling the exception in RestResponseEntityExceptionHandler.
Staketrace is not getting printed because you are handling the ResponseEntityExceptionHandler in the RestResponseEntityExceptionHandler by RestControllerAdvice and passing only the error message in response. It you want to print it specially then add a logger in your handleBadRequest method for the error i.e. e in your case.

Spring ExceptionHandler but for normal beans

I have been able to successfully use #ExceptionHandler annonated methodsorg.springframework.web.bind.annotation.ExceptionHandler in Controller Classes in my Spring projects to handle exceptions thrown by spring #RestController
Working example:
#Validated
#RestController
#RequestMapping(value = UrlsProperties.API_PATH, produces = MediaType.APPLICATION_JSON, consumes = { MediaType.APPLICATION_JSON })
#Api(value = "MyController", description = "MyController processing and forwarding controller")
public class MyController {
private static Logger log = LogManager.getLogger(MyController.class);
...
#JsonFormat
#ExceptionHandler(MissingServletRequestParameterException.class)
public ResponseMessage handleMissingParams(MissingServletRequestParameterException ex) {
String name = ex.getParameterName();
log.error(name + " parameter is missing");
return new ResponseMessage(400, ex.getMessage());
}
}
I am trying to achieve the same way of exception handling but for a normal bean, [ not a controller ]. Simply adding an #ExceptionHanlder annotated method did not seem to catch the exceptions thrown by that bean's methods.
My question is how to handle exceptions thrown by a bean by writing a method inside this bean?
#ExceptionHandler annotation is not for general exception handling. It's used in controllers to convert an exception into a proper HTTP response. It won't work for normal beans, because only controllers return a response.
If any code (doesn't need to be in a bean) throws an exception and you don't handle it, it would eventually propagate up to your controller's exception handler and it would be converted to a response. That would be poor design though, as you should handle exceptions as early as you can.
What you can do is create exceptions that are meant to be propagated to your exception handlers. Your code catches an exception, then re-throws it wrapped into your own exception (such as IllegalRequestException). The handler then returns an error code and details to the caller.

How can I customize exceptions thrown when #Produces and #Consumes is violated

I'm working on i18n(Internationalization and localization) task of my
REST services. Now I want to pass the error message according to the
Accept-Language of the header to the Exceptions thrown when Accept or
Content-Type of the header's not matched with #Produces and
#Consumes.
I found a solution in ContainerRequestFilter, but if I
check the Accept and Content-Type of the header in that
ContainerRequestFilter and throw Exception when it's not matched the
MediaType I want, there will be no need to use #Produces and
#Consumes again in the Resource.
So my question is, is there a way to
customize the exceptions thrown when #Produces and #Consumes is
violated (I mean NotAcceptableException and NotSupportedException)?
Because I want to pass the error message in multiple languages to the
message in these Exceptions.
You may use ExceptionMapper which will catch exceptions thrown in your service and return formatted response. It may be customized to handle specific exceptions.
#Provider
#Singleton
public class ExceptionMapperProvider implements ExceptionMapper<Exception> {
#Override
public Response toResponse(final Exception exception){
return Response.status(HttpStatusCodes.STATUS_CODE_SERVER_ERROR).entity(new BasicResponse(InternalStatus.UNHANDLED_EXCEPTION, exception.getMessage())).type(MediaType.APPLICATION_JSON).build();
}
}

ExceptionHandler with ResponseBody: set ResponseStatus in method body

I have a method to handle a particular class of exceptions in a Spring MVC environment.
The metod (simplified) implementation follows
#ExceptionHandler(AjaxException.class)
#ResponseStatus(value=HttpStatus.BAD_REQUEST)
#ResponseBody
public Exception handleException(AjaxException ex) {
return ex;
}
This is works fine, but to return a different ResponseStatus I have to create a new handling method.
Is it possible to change the response status inside the method body instead of using the #ResponseStatus annotation without changing the return type?
If not, is it possible to achieve the same result changing the return type (maybe serializing the exception class by myself and returning it as a string)?
Add the HttpServletResponse to the method signature and simply call the setStatus method.
#ExceptionHandler(AjaxException.class)
#ResponseBody
public Exception handleException(AjaxException ex, HttpServletResponse response) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return ex;
}
Something like that should work.
Easy done, reading a little more carefully the spring documentation.
It is possible to pass the HttpServletResponse as an object parameter. In such object is possible to set the return code. The syntax is as follows:
#ExceptionHandler(AjaxException.class)
#ResponseBody
public AjaxException handleException(AjaxException ex,HttpServletResponse response) {
//test code ahead, not part of the solution
//throw new NullPointerException();
//end of test code
response.setStatus(404);//example
return ex;
}
This will return the json serialization of the exception along with the specified http return code.
EDIT:
I deleted this answer yesterday because this solution didn't seem to work. The problem was a bit trickyer: when you manage an exception this way, if the method annotated with ExceptionHandler throws an exception itself then the thrown exception is ignored and the original exception is thrown instead.
My code was somehow like the solution I posted (it threw exception in the start of the method), so I couldn't see the json output, the standard spring exception handler was fired instead. To resolve I simply trycatched the exception-throwing line and everything was ok.

Categories

Resources