Returned JSON error from RESTful Spring API at 404 (Ambiguous @ExceptionHandler)
I am using Spring (4.0.4) MVC to build 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 a JSON error, 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 a stackoverflow question , I found that I can prevent this error page instead of sending the error by including the following .xml parameter in my website
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
And using a global advice like 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 get 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 problem is it doesn't know if my custom ExceptionHandler should be called or the one defined in the web.servlet.
How can I solve this so that I can return JSON from the API using Spring?
source to share
Here's what I think is going on:
Your class @ControllerAdvice
extends ResponseEntityExceptionHandler
, which has a method handleNoHandlerFoundException
(see the end of this file for the source code ) Also, you have a @ExceptionHandler annotated method to handle the same exception.
@Override
ResponseEntity handleNoHandlerFoundException(NoHandlerFoundException ex,
HttpHeaders headers, HttpStatus status, WebRequest request)
I think both of them in your code lead to this problem.
So either:
- Override this method (and don't use the @ExceptionHandler annotated method)
- do not extend ResponseEntityExceptionHandler. Use the @ExceptionHandler annotated method instead.
I think any of these options should work.
source to share
Try it.
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);
}
}
source to share