Imesh Chandrasiri
Imesh Chandrasiri

Reputation: 5679

Multiple exception handlers for ResponseBody methods and normal methods

I have a requirement where I want to handle how exceptions are returned. Depending on the type of the controller method if it is annotated with @ResponseBody a json string should be returned. Additionally if it is a String returning method a jsp error page should be returned.

However it seems that I am unable to define two global exception handler (with ControllerAdvice) both which handles Exception.class but one returns a ModelAndView and the other is annotated with @ResponseBody. I get an exception mentioning that it is too ambigious.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous @ExceptionHandler method mapped for [class java.lang.Exception]

The below code is an example of an ideal situation where both scenarios are handled

The methods

@RequestMapping(value = "/{pathValue}/page", method = RequestMethod.GET)
public String getPage(@PathVariable(value="pathValue") String pathValue, ModelMap model) throws Exception {

@RequestMapping(value = "{pathValue}/jsonData", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody ModelMap getJson(@PathVariable(value="pathValue") String pathValue) throws Exception { 

The Exception Handlers

@ExceptionHandler(Exception.class)
@ResponseBody ErrorInfo handleBadRequest(HttpServletRequest req, Exception ex) {

@ExceptionHandler(value = Exception.class)
public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception { 

in the above example the getPage method should be handled by handleBadRequest and getJson should be handled by defaultErrorHandler

Is there any way to configure two global exception handlers which both handle the same Exception class and returns a page or json based on the Controller method type.

Upvotes: 4

Views: 1913

Answers (1)

Robert Budźko
Robert Budźko

Reputation: 183

Not out of the box I suppose, because AbstractHandlerMethodExceptionResolver cannot do what you want. If I'm not mistaken then interface has no argument that could indicate method which has thrown particular instance of exception.

I remember that creating wrapping implementation (for example aspect) which was configurable with particular exception type has helped me in the past. Such a implementation will wrap every controller's method's call and catch all exceptions just to wrap it in configurable exception type and rethrow. In your case it would be something like JsonSomethingException and ResourceSomethingException.

Another option might be opposite (more low-level) approach. Note that in exception handling method you receive HttpServletRequest instance, so it is possible to browse some data about request. In you case @RequestMapping bases on this data to determinate which method should be called - you can do the same in exception handler! The best (imho) apprach would be to distinguish json and html by Content-Type header of HTTP protocol. In such situation writing single global error handler, which returns appropriate ResponseEntity based on Content-Type will be quite easy. Especially with addition of some json parser (for example Jackson).

Good luck :).

Upvotes: 3

Related Questions