Harshal
Harshal

Reputation: 193

ResponseEntityExceptionHandler is not getting called when exception occurs

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>

Upvotes: 13

Views: 36290

Answers (9)

Anurag Bhalekar
Anurag Bhalekar

Reputation: 981

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.

Upvotes: 0

NXT Dev
NXT Dev

Reputation: 91

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;
}

Upvotes: 0

Chinni Achari
Chinni Achari

Reputation: 1

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.

Upvotes: 0

Georgios Syngouroglou
Georgios Syngouroglou

Reputation: 19944

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.

Upvotes: 0

Maciej Dybek
Maciej Dybek

Reputation: 186

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){
    
}

Upvotes: 1

Rimeridius
Rimeridius

Reputation: 61

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 {
}

Upvotes: 0

Supun Wijerathne
Supun Wijerathne

Reputation: 12938

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.

Upvotes: 0

Brian Clozel
Brian Clozel

Reputation: 59056

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.

Upvotes: 18

Javasick
Javasick

Reputation: 2983

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

Upvotes: 3

Related Questions