I am developing a REST service using SpringMVC, where I have @RequestMapping at class and method level.
This application is currently configured to return error-page jsp configured in web.xml.
<error-page>
<error-code>404</error-code>
<location>/resourceNotFound</location>
</error-page>
I however want to return custom JSON instead of this error page.
I am able to handle exception and return json for other exceptions, by writing this in controller, but not sure how and where to write the logic to return JSON when the url does not exist at all.
@ExceptionHandler(TypeMismatchException.class)
@ResponseStatus(value=HttpStatus.NOT_FOUND)
@ResponseBody
public ResponseEntity<String> handleTypeMismatchException(HttpServletRequest req, TypeMismatchException ex) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage("error.patient.bad.request", null, locale);
errorMessage += ex.getValue();
String errorURL = req.getRequestURL().toString();
ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
return new ResponseEntity<String>(errorInfo.toJson(), headers, HttpStatus.BAD_REQUEST);
}
I tried @ControllerAdvice, it works for other exception scenarios, but not when mapping is not avaialble,
@ControllerAdvice
public class RestExceptionProcessor {
@Autowired
private MessageSource messageSource;
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
@ResponseStatus(value=HttpStatus.NOT_FOUND)
@ResponseBody
public ResponseEntity<String> requestMethodNotSupported(HttpServletRequest req, HttpRequestMethodNotSupportedException ex) {
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage("error.patient.bad.id", null, locale);
String errorURL = req.getRequestURL().toString();
ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
return new ResponseEntity<String>(errorInfo.toJson(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(NoSuchRequestHandlingMethodException.class)
@ResponseStatus(value=HttpStatus.NOT_FOUND)
@ResponseBody
public ResponseEntity<String> requestHandlingMethodNotSupported(HttpServletRequest req, NoSuchRequestHandlingMethodException ex) {
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage("error.patient.bad.id", null, locale);
String errorURL = req.getRequestURL().toString();
ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
return new ResponseEntity<String>(errorInfo.toJson(), HttpStatus.BAD_REQUEST);
}
}
If you are using Spring Boot, set BOTH of these two properties:
Now your @ControllerAdvice annotated class can handle the "NoHandlerFoundException", as below.
NOTE it is not sufficient to ONLY specify this property:
, as by default Spring maps unknown urls to /**, so there really never is "no handler found".
To disable the unknown url mapping to /**, you need
which is why the two properties TOGETHER produce the desired behavior.
If you're using spring 3.2 or later you can use a controller advice (
@ControllerAdvice
) to deal with, amongst other things, mapping errors (404's). You can find documentation here. Take a look at section 17.11. You can use this, for example, to provide more detailed logging on why your request bindings aren't being matched for specific urls, or to simply return a more specific response than a generic 404.you can return json in the location below,that /handle/404.
after you config this in web.xml,a 404 error will redirect to /handle/404,and you can create a controller with this mapping and return a json result. for example.
After digging around DispatcherServlet and HttpServletBean.init() in SpringFramework I see that its possible in Spring 4.
org.springframework.web.servlet.DispatcherServlet
throwExceptionIfNoHandlerFound is false by default and we should enable that in web.xml
And then you can catch it in a class annotated with @ControllerAdvice using this method.
Which allows me to return JSON response for bad URLs for which no mapping exist, instead of redirecting to a JSP page :)