3

I'm using Spring (4.0.4) MVC to build a RESTful API. I need to return a ResponseEntity with a JSON representation of an error with http status 404.

However, when I make a request that results in a 404, instead of seeing the error JSON, I get the following output:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /project/api/resource/100 was not found on this server.</p>
<p>Additionally, a 503 Service Temporarily Unavailable
error was encountered while trying to use an ErrorDocument to handle the request.</p>
</body></html>

From this stackoverflow post, I've found that I can prevent this error page from being sent in place of the the error by including the following parameter in my web.xml

<init-param>
    <param-name>throwExceptionIfNoHandlerFound</param-name>
    <param-value>true</param-value>
</init-param>

And using the a global advice similar to this:

@ControllerAdvice
public class MyExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    @ResponseBody
    public ResponseEntity<ErrorResponse> requestHandlingNoHandlerFound(HttpServletRequest req,
            NoHandlerFoundException ex) {

        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setText("error response");
        return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.BAD_REQUEST);
    }
}

However, when I add this MyExceptionHandler class, I am getting the following exception:

Caused by: java.lang.IllegalStateException: Ambiguous @ExceptionHandler method mapped for [class org.springframework.web.servlet.NoHandlerFoundException]: {public org.springframework.http.ResponseEntity com.rest.MyExceptionHandler.requestHandlingNoHandlerFound

The issue is that it doesn't know whether to call my custom ExceptionHandler or the one defined in web.servlet.

How can I resolve this issue so that I am able to return JSON from an API using Spring?

2 Answers 2

6

Here's what I think is happening:

Your @ControllerAdvice class extends ResponseEntityExceptionHandler which has a method handleNoHandlerFoundException (see at the end of the this file in the source code) Also, you have an @ExceptionHandler annotated method to handle the same exception.

@Override
ResponseEntity handleNoHandlerFoundException(NoHandlerFoundException ex,
            HttpHeaders headers, HttpStatus status, WebRequest request)

I think having both of them in your code is causing this issue.

So either:

  1. Override that method (and don't use the @ExceptionHandler annotated method)
  2. do not extend ResponseEntityExceptionHandler. Use the @ExceptionHandler annotated method instead.

I think either of those options should work.

Sign up to request clarification or add additional context in comments.

3 Comments

Unfortunately neither solution 1 nor 2 resolved the problem I was having. I think the issue is that the ResponseEntityExceptionHandler class defines a final handler for the NoHandlerFoundException that can't be overridden. Does anyone have any other suggestions on how I can return error JSON with Spring REST or how to overcome the ambiguous @ExceptionHandler problem?
You're right. I wrote some sample code and was able to reproduce this issue. Are you using Spring Boot or is this a regular Spring MVC webapp?
@Jigish's response worked great for me. I opted for solution 2, which worked well in my Spring Boot 1.5.6 app. No complaints from the framework, and my handler returned the error JSON that I was expecting.
-1

Try this.

package x.y.z;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.NoHandlerFoundException;

@ControllerAdvice
public class MyExceptionHandler {

    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(value=HttpStatus.NOT_FOUND)
    @ResponseBody
    public ResponseEntity<String> handle404() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);

        String json = "{\"error\":\"Resource not found.\"}";

        return new ResponseEntity<String>(json, headers, HttpStatus.NOT_FOUND);
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.