Spring REST API custom exceptions handling - spring

I have a Spring 3.2 application and I've created a REST API based on Spring MVC. I am using #ControllerAdvice annotation for custom exceptions handling. For example:
#ControllerAdvice
public class RestResponseEntityExceptionHandler {
#ExceptionHandler(MyCustomException.class)
#ResponseStatus(HttpStatus.CONFLICT)
#ResponseBody
public ExceptionMessage handleMyCustomException(MyCustomException ex){
return new ExceptionMessage(ex.getClass().getName(), ex.getMessage(), ex.getExceptionCode());
}
}
The issue is that I see how my custom exception is thrown but the exception handler method is actually not being executed and hence my exception message is not returned to the client. Instead, I noticed in the logs how the DefaultHandlerExceptionResolver handles the exception (with a Spring generic one, ServletRequestBindingException in a GET method). How can I get rid of this issue?
Thanks!

The ServletRequestBindingException is a hint that something went wrong before the handler method of the controller. In this case some binding issue.
Exception handlers annotated with #ExceptionHandler are only called when an exception is thrown within a controller handler method (#RequestMapping).

Related

spring boot application exception handler which don't have controller

My Spring boot app is standalone application which don't have controller. I am calling service layer from main method of spring boot application.
I have tried to use #ExceptionHandler #ControllerAdvice annotations in my class as below. but control never comes to My Exception Handler method
package com.test.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
#ControllerAdvice
public class MyExceptionHandler {
#ExceptionHandler(NullPointerException.class)
public void handleNullpointerExcetion() {
System.out.println("Handling Null pointer exception");
}
}
Tried with package name as well which i need to scan in #ControllerAdvice but it is not working
#ControllerAdvice("com.test.utility")
public class MyExceptionHandler {
#ExceptionHandler(NullPointerException.class)
public void handleNullpointerExcetion() {
System.out.println("Handling Null pointer exception");
}
}
Are we not able to handle exception at centralized place if i we don't have controller class which we annotate with #RestContoller or #Controller
I don't think so.
ControllerAdvice is only used whenever a controller would return an exception,
It is a layer that exists after your endpoint in the controller returns and before actually returning the response, to interject and globally handle the exception and is meant to be global only for controllers.
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html
since you don't have a controller, I'd imagine the ControllerAdvice will not help you there.
If you want a centralized error handling mechanism, you'd have to implement something similar to the controller advice yourself around your "Main" function, to which you can have unified exception handling responses.

Exception is not thrown for page doesn't exist

I have defined ExceptionHandler with #ControllerAdvice and catches the following
Exception.class, Throwable.class, SQLException.class
When a user enters a page which doesn't exist or not available in the server. circular view page error is being displayed in the log and ExceptionHandler is not getting called.
What are the usual checkpoints to make the API error to get caught in CustomExceptionHandler. Not sure whether any tomcat hooks to be defined.
Using Spring Boot 2.0 and Spring version 5.0
Thanks.
In case : user enters a page/resource which does not exist, no exception is thrown. So your code does not work (I believe your code is similar to following code)
#ControllerAdvice
public class ErrorHandler {
#ExceptionHandler(Exception.class)
public String handle() {
....
return "error"
}
}
In order to make it work you need to extend yourhandler class from ResponseEntityExceptionHandler as
#ControllerAdvice
public class ErrorHandler extends ResponseEntityExceptionHandler {
...
}
And You need to override the following method
handleHttpMediaTypeNotSupported
handleHttpMediaTypeNotSupported
Detailed guide can be found from
- https://blog.jayway.com/2013/02/03/improve-your-spring-rest-api-part-iii/
- http://www.baeldung.com/global-error-handler-in-a-spring-rest-api
Another way, You can override /error if there is fixed message in all general cases.

Spring Boot treat 404 as regular exception

Rather than have an error page for a 404 I'd like to treat it like a normal exception in my Spring Boot application. Is there any way to treat the 404 errors as an exception instead of having it forward to the /error page.
My overall goal is basically to treat this using my existing:
#ControllerAdvice
#RestControllerAdvice
public class MyClass {
#ExceptionHandler (...)
public ResponseEntity<?> doStuff(Throwable t) {
// ...
}
}
By default Spring doesn't throw exception when page/resource is not found (NoHandlerFoundException), so there is nothing to handle.
You can override this behaviour by switching this configuration property to true:
spring.mvc.throw-exception-if-no-handler-found=true
After that you can implement your own handler for NoHandlerFoundException.

How exactly work the HandlerExceptionResolver interface in Spring? Can I show an error page when the user try to access to a not mapped resource?

I am studying how to handle custom exception in Spring on a tutorial that show me this class named ExceptionHandler that implement the HandlerExceptionResolver Spring interface:
#Component
public class ExceptionHandler implements HandlerExceptionResolver {
private static final Logger logger = LoggerFactory.getLogger(ExceptionHandler.class);
#Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception) {
System.out.println("Spring MVC Exception Handling");
logger.error("Error: ", exception);
return new ModelAndView("error/exception","exception","ExceptionHandler message: " + exception.toString());
}
}
And then, into a controller class of the example, it throws this exception in this way:
#RequestMapping(value="/throwRunTimeException", method=RequestMethod.GET)
public void throwException() {
throw new RuntimeException();
}
So I have some doubts about how exactly do this class.
I can't understand if implementing the HandlerExceptionResolver interface I am declaring a new specific exception type or if simply specify a specific behavior that happens when a generic runtime exception is thrown.
It seems me the second situation...I think that, in the previous example, when a generic RuntimeException is thrown it return an exception.jsp page (and the related message that have to be shown into the model object).
So, if the previous assertion is true, can I use this method for the following pourpose?
I think that when a user try to open an URL that is it not mapped to any controller method a RuntimeException is thrown.
So, into the **resolveException()** method, can I extract the required URL from the HttpServletRequest request input parameter and use it to show a specific error message (that indicate that this URL not exist) into the returned view?
I don't think that is possible. When the DispatcherServlet can't find the url mapped in one of your controllers, it will throw a NoHandlerFoundException. This will then be forwarded to your servlet container like Tomcat which handles the error and shows the 404 page for example. You can change this behaviour by adding the following to your web.xml:
`
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/jsp/404error.jsp</location>
</error-page>
`
Note that it's not possible yet to configure this in JavaConfig.
For other Exceptions that are thrown you can use the HandlerExceptionResolver to return the desired view.
You could also use the #ExceptionHandler annotation on a method in your controller to catch the exceptions and handle them appropriately. This can be combined with the #ControllerAdvice annotation to enable this for every controller.

How can I bypass Grails exception handling, in order to use Spring Oauth2?

I am trying to port an Oauth2 client based on Oauth for Spring Security from plain Java/Spring to Grails, and have run into a problem. The crux of the issue appears to be the fact that the design of the Spring Oauth client implementation relies on the assumption that an exception thrown from the Oauth2RestTemplate will be caught in a catch block of the OAuth2ClientContextFilter, thus allowing the filter to issue a redirect response (to send an authorization request to the oath provider).
This works fine in plain Java/Spring but in Grails, the GrailsDispatcherServlet is configured to handle all exceptions via HandlerExceptionResolvers. Thus the exception thrown in the Oauth2RestTemplate (invoked inside a Grails controller) is caught by the GrailsExceptionResolver and is never seen by the OAuth2ClientContextFilter, thus defeating the desired redirect behavior.
All discussions I have found of customizing Grails exception handling all seem to assume that the purpose of the customization is to map the exception to an HTTP error code or to a error page view. But is there some way to tell Grails to simply allow a particular exception to flow through unhandled, so that it can be caught by the servlet filter? Or is it possible to insert a custom HandlerExceptionResolver that re-throws the exception rather than returning a ModelAndView (as is the standard expectation for a HandlerExceptionResolver)? Or is there some other better way to get the Oauth for Spring Security client working inside Grails?
Here's what I eventually came up with. Not sure if it is the best solution but it seems to work:
Create a new MyDispatcherServlet.groovy:
package org.example.com
import org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.springframework.web.servlet.ModelAndView
import org.springframework.security.oauth2.client.UserRedirectRequiredException
class MyDispatcherServlet extends GrailsDispatcherServlet {
#Override
protected ModelAndView processHandlerException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) throws Exception {
def e = ex
while (e) {
if (e instanceof UserRedirectRequiredException) {
throw ex
}
e = e.cause
}
return super.processHandlerException(request, response, handler, ex)
}
}
Run grails install-templates and modify the web.xml to use MyDispatcherServlet instead of the default GrailsDispatcherServlet
The result is that MyDispatcherServlet will re-throw an exception that contains a UserRedirectRequiredException so that it can be caught by the OAuth2ClientContextFilter, but other exceptions will be passed on and handled as before by the GrailsExceptionResolver.
I think you can declare exceptionHandler in resources.groovy by defining your custom exception resolver. This custom exception resolver can (optionally) override GrailsExceptionResolver
exceptionHandler(MyExceptionResolver) {
exceptionMappings = ['java.lang.Exception': '/error']
}
class MyExceptionResolver extends GrailsExceptionResolver {
#Override
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
//your custom code
return super.resolveException(request, response, handler, ex)
}
}

Resources