Capture Spring MVC DispatcherServlet exceptions with ExceptionResolver - java

I am trying to return a valid JSON body for every request of an Spring MVC service, both correct and invalid.
Using #ExceptionHandler and a combination of ExceptionHandlerExceptionResolver, DefaultHandlerExceptionResolver and my own AbstractHandlerExceptionResolver I am able to process and set a body for almost all invalid requests that are dispatched to a valid controller or rejected by Spring Security.
However, errors thrown by the DispatcherServlet like noHandlerFound, can't be intercepted, so the response has a valid HTTP status code like 404, but the body contains the Tomcat default XML error.
Anybody knows how to set up or configure an Spring Exception Resolver so all failed requests are intercepted and a valid JSON body could be set?

There is a section explaining how is spring handling exception resolver for dispatcher servlet:
The dispatcher's exception resolution strategy can be specified via a
HandlerExceptionResolver, for example mapping certain exceptions to
error pages. Default are AnnotationMethodHandlerExceptionResolver,
ResponseStatusExceptionResolver, and DefaultHandlerExceptionResolver.
These HandlerExceptionResolvers can be overridden through the
application context. HandlerExceptionResolver can be given any bean
name (they are tested by type).
to be able to support Dispatcher exception handling overriding you have to implement HandlerExceptionResolver and Ordered class and declare the implementation as spring bean. You must return getOrder value as Integer.MIN_VALUE to override any other existing handler.

Related

Unexpected behaviour when Customizing ExceptionResolver in spring

Through the documentation of spring framework, I got to know about customizing exception handling mechanism of spring application. As per the documentation, It is stated that spring provides some default exception Resolvers.
SimpleMappingExceptionResolver
A mapping between exception class names and error view names. Useful for rendering error pages in a browser application.
DefaultHandlerExceptionResolver
Resolves exceptions raised by Spring MVC and maps them to HTTP status codes. See also alternative ResponseEntityExceptionHandler and REST API exceptions.
ResponseStatusExceptionResolver
Resolves exceptions with the #ResponseStatus annotation and maps them to HTTP status codes based on the value in the annotation.
ExceptionHandlerExceptionResolver
Resolves exceptions by invoking an #ExceptionHandler method in a #Controller or a #ControllerAdvice class. See #ExceptionHandler methods.
But in my requirement, I do not want the support of all these resolvers I just want ExceptionHandlerExceptionResolver to handle the exception in my Spring Application. So for that, I have added the following Configuration in my DispatcherServlet.
DispatcherServlet related configuration.
public void onStartup(ServletContext servletCxt) throws { ServletException {
......
dServlet.setDetectAllHandlerExceptionResolvers(false);
dServlet.setThrowExceptionIfNoHandlerFound(false);
.....
}
And in my Bean configuration java class, I have created following bean.
#Bean(name=DispatcherServlet.HANDLER_EXCEPTION_RESOLVER_BEAN_NAME)
HandlerExceptionResolver customExceptionResolver ( ) {
return new ExceptionHandlerExceptionResolver();
}
In the documentation, it is stated that
/**
* Set whether to detect all HandlerExceptionResolver beans in this servlet's context. Otherwise,
* just a single bean with name "handlerExceptionResolver" will be expected.
* Default is "true". Turn this off if you want this servlet to use a single
* HandlerExceptionResolver, despite multiple HandlerExceptionResolver beans being defined in the context.
*/
But even after all such configuration, I see HTML error pages and not JSON error response.
Sample ExceptionHandler method.
#ExceptionHandler(value={NullPointerException.class})
public ResponseEntity<Object> nullPointerExceptionHandler(NullPointerException e){
logger.info("local exception resolver running");
Map<String,Object> map=new HashMap<String,Object>(6);
map.put("isSuccess",false);
map.put("data",null);
map.put("status",HttpStatus.INTERNAL_SERVER_ERROR);
map.put("message", e.getMessage());
map.put("timestamp",new Date());
map.put("fielderror",null);
return new ResponseEntity<Object>(map,HttpStatus.BAD_GATEWAY);
}
What I am doing wrong? I only need the support of ExceptionHandlerExceptionResolver throughout my spring application to maintain consitency.

Prevent a InternalServerErrror while using BeanValidation

I am using BeanValidation (with DropWizzard). Now if a form contains a field annotated with #NotEmpty, but is empty, I'll get an InternalServer ErrorException with Status Code 500.
I'd like to log a RuntimeException for this and forward the user to an error page.
Is it possible to catch all ValidationException in one place, log them and do something like forwarding the user?
You can build your own exception mapper for the ValidationException. Jersey have its own ValidationExceptionMapper implementation that will return a bad request if the element is a parameter that is validated or a internal server error if the validation occur on a return value. Latest version of Dropwizard should configure these mappers by default.
To build your own exception mapper you should implement the interface javax.ws.rs.ext.ExceptionMapper and register it in the jersey context of Dropwizard ieenvironment.jersy().register(MyExceptionMapper.class)if you use Dropwizard 0.8 or later

what's difference between Controller and Handler in Spring MVC?

The documentation of Spring MVC sometimes says about "handlers" or "request handlers". For instance, http://docs.spring.io/autorepo/docs/spring/4.0.4.RELEASE/javadoc-api/org/springframework/web/servlet/handler/SimpleUrlHandlerMapping.html says:
Implementation of the HandlerMapping interface to map from URLs to request handler beans
And sometimes it says about controllers. For instance, there is an interface called org.springframework.web.servlet.mvc.Controller ( http://docs.spring.io/spring-framework/docs/2.5.x/api/org/springframework/web/servlet/mvc/Controller.html ).
My question is: are Controllers and Handlers the same?
Generally speaking, a Controller is Handler, but a Handler doesn't have to be a Controller.
For example, HttpRequestHandler, WebRequestHandler, MessageHandler are all handlers which can work with the DispatcherServlet. ( (#)Controller is a handler for executing a web request and returning a view.)
Shortly, Handler is just a term, it is neither a class nor interface. And it is responsible for executing the Mapping.
A Controller is a specific type of Handler but not all Handlers are Controllers.
To execute a type of Handler there is a HandlerAdapter and for each type of Handler there is a different HandlerAdapter. You have Controller and #Controller, HttpRequestHandler and also a plain Servlet can be a Handler. Or if you have some custom things you can even implement your own.
Handler is a inclusive i.e. covering all the services details.
Controller is an an exclusive implementation.
In Spring we have the following different types of handlers:
HandlerMapping: The HandlerMapping strategy is used to map the HTTP client request to some handler controller(or controllers) and/or method. This is done based on the request URL and the HTTP method, but may also include the request parameters, request headers, or other custom factors.
For example: DefaultAnnotationHandlerMapping, SimpleUrlHandlerMapping, BeanNameUrlHandlerMapping.
HandlerAdapter: The DispatcherServlet uses a HandlerAdapter to invoke a method. Which is decouples the DispatcherServlet from controller implementations classes.
For example: AnnotationMethodHandlerAdapter, HttpRequestHandlerAdapter, RequestMappingHandlerAdapter, SimpleControllerHandlerAdapter, SimpleServletHandlerAdapter

Handling invalid URL's when using #ParamValue in Spring MVC

I am using #ParamValue annotation in my controller (Spring MVC).
Say My valid URL's are:
www.temp.com/test/a,
www.temp.com/test/b and
www.temp.com/test/c
So, my RequestMapping is:
#RequestMapping(value = "/test/{value}", method = RequestMethod.GET)
Now, my problem is that if anyone types a wrong URL like this :
www.temp.com/test/youarebroken
then I have to manually handle such a case in my controller to show 404 or not found.
Isn't there something inbuilt that sends a "not found or 404" notification to server that I can use directly ?
The simplest solution is to define a custom exception handler and to throw the custom exception when a validation fails within your controller. That would require that you manage the conditions manually as you stated you do not want to do.
A different solution is to use a global exception handler and define it to deal with the HTTP errors that are handled by Spring built-in.
In this link you can see both approaches: http://www.journaldev.com/2651/spring-mvc-exception-handling-exceptionhandler-controlleradvice-handlerexceptionresolver-json-response-example
However, from your question I understand you would like to return automatically an exception when certain condition in your param value does not meet, and you do not want to validate this manually within your controller. For this, you can add custom validation for an specific class and then set #Valid before the #ParamValue.
You can check this link for DataBinding http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html
And this link for specific validation on param attributes: Spring Web MVC - validate individual request params
So, in plain a solution would be to define a custom validator that throws a custom exception when fails. To set #Valid for the parameters (check link) and to adjust the custom exception to handle HTTP errors (e.g. HttpStatus.NOT_FOUND).
You can use a regex in your #RequestMapping URL. Example:
#RequestMapping(value = "/test/{value:[a-z]}", method = RequestMethod.GET)

#ControllerAdvice methods seem to bypass interceptors

I have a class annotated with #ControllerAdvice with some central exception handling for my api. One of the exceptions it handles is the MethodArgumentNotValidException which gets thrown when a request method parameter annotated with #Valid, fails validation.
In my application, I also have a CORS interceptor setup which adds the "Access-Control-Allow-Origin" header to the servlet response when the request is successful. However, it seems that when validation fails on the parameter annotated with #Valid, my interceptor gets bypassed. My exception handler needs to send back error information for form fields that are invalid so they can be dealt with in the browser.
Just wondering if this is normal behaviour that my interceptor gets bypassed when an exception is thrown, or if I'm missing some configuration in the #ControllerAdvice class.
This is indeed normal behavior.
From the javadoc of HandlerInterceptor.postHandle
Intercept the execution of a handler. Called after HandlerAdapter actually invoked the handler, but before the DispatcherServlet renders the view. Can expose additional model objects to the view via the given ModelAndView.
DispatcherServlet processes a handler in an execution chain, consisting of any number of interceptors, with the handler itself at the end. With this method, each interceptor can post-process an execution, getting applied in inverse order of the execution chain.
Arguably the MethodArgumentNotValidException is thrown before the method is actually called, it is called in preparing the actual method call. Actually the postHandle is only executed after successful execution/invocation of the method. In case of an exception only the preHandle and afterCompletion methods are called.

Categories