ResponseEntityExceptionHandler is not getting called when exception occurs
Asked Answered
D

9

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>
Dittman answered 21/6, 2014 at 5:55 Comment(5)
Did you ever find a solution to your issue?Bower
I got the same issue...Blasien
I think your methods in RestResponseEntityExceptionHandler will get used only if they override methods from ResponseEntityExceptionHandler.Ice
my controller advice class was in different package. After copying it in controllers package it workedDittman
May be because you didn't declare your RestResponseEntityExceptionHandler as @RestControllerHerbart
P
18

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.

Ploy answered 30/6, 2015 at 21:13 Comment(3)
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.Shimmy
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 hereDurward
What about Security exceptions?Raynard
S
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

Stand answered 18/4, 2016 at 8:43 Comment(0)
M
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){
    
}
Machinery answered 9/7, 2020 at 19:26 Comment(0)
M
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.

Mate answered 8/2, 2018 at 5:50 Comment(1)
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.Modiolus
B
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 {
}
Bohemianism answered 8/4, 2020 at 17:53 Comment(0)
F
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.
Fiend answered 22/1, 2021 at 12:1 Comment(2)
if ResponseEntityExceptionHandler::handleException is not hit, what could be the issue? I've already checked the package names - everything seems to be fine.Bodiless
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.Fiend
M
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.

Meadowlark answered 9/6, 2022 at 4:57 Comment(0)
A
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;
}
Ancy answered 24/8, 2022 at 7:32 Comment(0)
R
0

If you have copied the GlobalExceptionHandler from some tutorial, mind that the functions written in "ResponseEntityExceptionHandler" are different in different spring versions and different functions are called for the same error across different spring version.

Example in version 2.2.0.RELEASE, spring calls method "handleMethodArgumentTypeMismatch" but in version 2.6.6 (if you send a string in request body for a long declared field), spring's class "ResponseEntityExceptionHandler" doesn't even have the "handleMethodArgumentTypeMismatch" method declared, instead it calls the "handleHttpMessageNotReadable" method.

To go about this, simply generate the @Override methods that come compiled with the class.

Raseta answered 11/9, 2023 at 11:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.