13

I am new to spring. I am developing a REST api with spring webmvc. For Error Handling I got this link http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-ann-rest-spring-mvc-exceptions

I have tried to use ResponseEntityExceptionHandler in my project . but whenever my controller throws exception it never reaches to this ResponseEntityExceptionHandler.

Following are my code snippet

Controller

@Controller
@RequestMapping("/hello")
public class HelloController {  
    private static final Logger logger = Logger.getLogger(HelloController.class);
    @RequestMapping(value="/{name}", method=RequestMethod.GET)
    public @ResponseBody String greet(@PathVariable(value = "name")String name ) throws InvalidInputException, ResourceNotFoundException{
        logger.info("start greet() "+name );
        System.out.println("start greet() "+name);
        String message = null;
        if("".equalsIgnoreCase(name))
        {
            throw new InvalidInputException("Invalid Input");
        }
        List<String> names = new ArrayList<String>();
        names.add("Harshal");
        names.add("Smitesh");
        if(names.contains(name)){
            message = "Hello "+ name;
        }else{
            throw new ResourceNotFoundException("Requested Resource not found");
        }
        System.out.println("end greet");
        logger.info("end greet()");
        return message;
    }
}

Exceptions

package com.practice.errorhandlerdemo.exception;

public class InvalidInputException extends RuntimeException{
    private static final long serialVersionUID = 5489516240608806490L;
    public InvalidInputException() {
        super("Invalid Input");
    }
    public InvalidInputException(String message) {
        super(message);
    }
}

package com.practice.errorhandlerdemo.exception;

public class ResourceNotFoundException extends RuntimeException {
    private static final long serialVersionUID = -4041009155673754859L;
    public ResourceNotFoundException() {
        super("requested resource not found");
    }
    public ResourceNotFoundException(String message) {
        super(message);
    }
}

exceptionhandler

@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
    private static final Logger logger = Logger.getLogger(RestResponseEntityExceptionHandler.class);
    @ExceptionHandler(value={ResourceNotFoundException.class})
    @ResponseStatus(value=HttpStatus.NOT_FOUND)
    protected ResponseEntity<Object> handleResourceNotFound(RuntimeException ex, WebRequest request){
        logger.info("start handleResourceNotFound()");
        String bodyOfResponse = "Requested resource does not found";
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        return handleExceptionInternal(ex, bodyOfResponse, httpHeaders, HttpStatus.NOT_FOUND, request);
    }

    @ExceptionHandler(value={InvalidInputException.class})
    @ResponseStatus(value=HttpStatus.BAD_REQUEST)
    protected ResponseEntity<Object> handleInvalidInput(RuntimeException ex, WebRequest request){
        logger.info("start handleInvalidInput()");
        String bodyOfResponse = "Invalid Input";
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        return handleExceptionInternal(ex, bodyOfResponse, httpHeaders, HttpStatus.BAD_REQUEST, request);
    }
}

dispatcher servlet

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd">

   <context:component-scan base-package="com.practice.errorhandlerdemo.controller"/>
   <context:annotation-config/>  

</beans>

web.xml

<web-app>
    <display-name>ErrorHandlerDemo</display-name>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/my-servlet.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
Georgios Syngouroglou
  • 18,813
  • 9
  • 90
  • 92
Harshal
  • 193
  • 1
  • 2
  • 9

8 Answers8

17

First, check that your @ControllerAdvice annotated class is taken into account by your configuration: is it located in a package that's scanned by Spring? Did you declare it as a bean in any other way?

Also, you don't need to extend ResponseEntityExceptionHandler if you don't need all the exception mappings it provides.

A simpler way to write your exception handling:

@ControllerAdvice
public class RestResponseEntityExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    protected ResponseEntity<String> handleResourceNotFound(ResourceNotFoundException ex){

      return ResponseEntity
              .status(HttpStatus.NOT_FOUND)
              .body("Requested resource does not found");
    }

    @ExceptionHandler(InvalidInputException.class)
    protected ResponseEntity<String> handleInvalidInput(InvalidInputException ex){

      return ResponseEntity
              .badRequest()
              .body("Invalid Input");
    }
}

Note that the ResponseEntity builder API has been in introduced in Spring 4.1, but you can use the regular constructor on 4.0.x.

Brian Clozel
  • 56,583
  • 15
  • 167
  • 176
  • Why would anyone downvote this answer without an explanation? `ResponseEntityExceptionHandler` does bring extra handlers but you don't necessarily need to extend it. The key is to have `@ControllerAdvice` and write your own `@ExceptionHandler` annotated methods. – amertkara Nov 20 '15 at 17:39
  • 4
    I downvoted it because the question is how to get ResponseEntityExceptionHandler working, not do I need one in the first place. The 'if' in this answer, shows it is wrong and shouldn't be here – dezzer10 Nov 07 '16 at 09:00
  • What about Security exceptions? – Bato-Bair Tsyrenov Apr 26 '17 at 02:56
3

I got the same issue in Spring WebMVC 4.2.5. The reason was throwExceptionIfNoHandlerFound parameter of DispatcherServlet. By default it's value is false, so all errors generates HttpServletResponse.SC_NOT_FOUND servlet response and no exceptions throwes.

After I set it to true, my @ExceptionHandlers started to work

Javasick
  • 2,753
  • 1
  • 23
  • 35
1

The issue is that your @ExceptionHandler declares ResourceNotFoundException whereas as a parameter to the handleResourceNotFound you expect RuntimeException. The parameter exception and the value of ExceptionHandler should match.

So it should be:

@ExceptionHandler(value={ResourceNotFoundException.class})
protected ResponseEntity<Object> handleResourceNotFound(ResourceNotFoundException ex, WebRequest request){
    
}
Maciej Dybek
  • 186
  • 8
0

There are some reported situations where both ResponseEntityExceptionHandler and @ControllerAdvice didn't work.

Both of them are supposed to compile the methods annotated with @ExceptionHandler under the class into a common place where all the controllers can refer from.

If it doesn't work for you. You can add you @ExceptionHandler methods into a common AbstractController class which is extended by all other controllers.

Supun Wijerathne
  • 11,964
  • 10
  • 61
  • 87
  • A `@ControllerAdvice` annotated class which `extends ResponseEntityExceptionHandler` might cause problems if you want to handle all exceptions like `@ExceptionHandler(Throwable.class)`, but haven't overridden the methods that are already defined in the base class. It contains some default methods of handling exceptions in cases like `404` or other `4**` cases like a missing URI parameter. In this case they will be handled in the default way unless overridden AND it is not exactly clear from the logs that *your* class is the one being used, but by extending, it contains these default methods. – Snackoverflow Mar 18 '19 at 21:37
0

You just need some configuration

In the application.properties or application.yml :

server.error.whitelabel.enabled=false
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

on springboot load your configuration file :

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "xx.xxx.xxxx")
@PropertySource("classpath:application.yml")
public class WebAppConfig {
}
Rimeridius
  • 61
  • 1
  • 1
0

Some workarounds,

  • Double check that you use the correct signature for your overriding method.
  • If you use any IDE, check if there is any @Override mark/sign/arrow that will ensure your override is valid.
  • Check if you already extend the ResponseEntityExceptionHandler from another class of your project OR from any other class of your dependencies.
  • Put a breakpoint to the ResponseEntityExceptionHandler::handleException method.
  • For the NoHandlerFoundException you should configure the DispatcherServlet to throw and exception if it doesn't find any handlers, link here.
Georgios Syngouroglou
  • 18,813
  • 9
  • 90
  • 92
  • if `ResponseEntityExceptionHandler::handleException` is not hit, what could be the issue? I've already checked the package names - everything seems to be fine. – Anand Rockzz Aug 18 '21 at 19:18
  • There are some different approaches for Error Handling in Spring. Subclassing the `ResponseEntityExceptionHandler` is one of them. For a fast check, find and put a break point anywhere you use the `@ExceptionHandler` of `@ControllerAdvice` annotations. Further info [here](https://www.baeldung.com/exception-handling-for-rest-with-spring). – Georgios Syngouroglou Aug 19 '21 at 20:09
0

Provide an @ExceptionHandler method for handling internal Spring MVC exceptions. This method returns a ResponseEntity for writing to the response with a message converter, in contrast to DefaultHandlerExceptionResolver which returns a ModelAndView.

Farhan Nasim
  • 773
  • 4
  • 13
0

To improve on @Javasick's answer which worked for me.

How to setThrowExceptionIfNoHandlerFound to true.

public class AppSetting extends AbstractAnnotationConfigDispatcherServletInitializer {
@NonNull
@Override
protected DispatcherServlet createDispatcherServlet(@NonNull WebApplicationContext servletAppContext) {
    final DispatcherServlet servlet = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
    servlet.setThrowExceptionIfNoHandlerFound(true);
    return servlet;
}
NXT Dev
  • 71
  • 4