0

I am writing a server-side REST application for a mobile app. I have been trying to setup an exception handler which follows the explanation here, where instead of showing some HTTP error page, the client receives a JSON object similar to this one:

{
    "status": 404,
    "code": 40483,
    "message": "Oops! It looks like that file does not exist.",
    "developerMessage": "File resource for path /uploads/foobar.txt does not exist.  Please wait 10 minutes until the upload batch completes before checking again.",
    "moreInfo": "http://www.mycompany.com/errors/40483"
}

I have modeled my exception on those detailed in the guide, and they seem to be working well (the custom errors are being shown in the console). But I got stuck at this point, because I don't know where I'm supposed to put the bean configuration.

Given that I have all my exception handlers, resolvers, etc., I thought I'd try go around it differently. At this point I would still get Spring's Whitelabel error page when I entered an invalid HTTP request, but this time with my custom error messages from my exceptions. So I figured if I tried to implement my own ErrorHandler as explained here, I might be able to construct the JSON objects using Gson or something, instead of the way the previous article went about it.

I tried to get a bare minimum ErrorHandler working:

package com.myapp.controllers;

import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

@RestController
public class ErrorMessageController implements ErrorController {

    private static final String ERROR_PATH = "/error";

    @Override
    public String getErrorPath(){
        return ERROR_PATH;
    }

    @RequestMapping(value = ERROR_PATH)
    public String renderErrorPage(HttpServletRequest request){

        String errorPage = (String) request.getAttribute("javax.servlet.error.status_code");

        return errorPage;
    }

}

So I expected to get something like a solitary 404 appearing on the webpage. But instead I'm getting a Tomcat error page:

Tomcat Error Page

Why is this? I'd appreciate any help.

1 Answer 1

1

This happens because request.getAttribute("javax.servlet.error.status_code") should be an Integer and you're casting it as a String. This causes an error during the error handling, which pops up the default Tomcat error handler.

If you cast it as an int, it will work:

@RequestMapping(value = ERROR_PATH)
public int renderErrorPage(HttpServletRequest request){

    int errorPage = (int) request.getAttribute("javax.servlet.error.status_code");

    return errorPage;
}

Alternatively, if you just want to return certain JSON structure, you could use @ExceptionHandler methods in stead of implementing an ErrorController.

For example, let's say you have the following controller:

@GetMapping
public String getFoo() throws FileNotFoundException {
    throw new FileNotFoundException("File resource for path /uploads/foobar.txt does not exist");
}

If you want to handle all FileNotFoundExceptions in a particular way, you could write a method with the @ExceptionHandler annotation:

@ExceptionHandler(FileNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse notFound(FileNotFoundException ex) {
    return new ErrorResponse(HttpStatus.NOT_FOUND.value(), 40483, "Oops! It looks like that file does not exist.", ex.getMessage(), "http://www.mycompany.com/errors/40483");
}

In this case, ErrorResponse is a POJO containing the fields you want. If you want to re-use this for all your controllers, you can put this in a @ControllerAdvice.

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

2 Comments

So where do I put the @ExceptionHandler method? In a new RestController?
You can choose it. If it only applies to a single controller, then you can put that method in the same controller class. If it applies to all controllers, then you create a new simple class and just annotate it with @ControllerAdvice and nothing else.

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.