Spring RestTemplate - Overriding ResponseErrorHandler

user3670450 picture user3670450 · May 23, 2014 · Viewed 52.4k times · Source

I am calling a ReST service through RestTemplate and trying to override ResponseErrorHandler in Spring 3.2 to handle custom error codes.

CustomResponseErrroHandler

public class MyResponseErrorHandler implements ResponseErrorHandler {

    @Override
    public boolean hasError(ClientHttpResponse response) throws IOException {
        boolean hasError = false;
        int rawStatusCode = response.getRawStatusCode();
        if (rawStatusCode != 200){
            hasError = true;
        }
        return hasError;
     }

    @Override
    public void handleError(ClientHttpResponse response) throws IOException {
        //String body = IOUtils.toString(response.getBody());
        throw new CustomServiceException(response.getRawStatusCode() , "custom Error");
   }
}

Spring framework invokes hasError method but not handleError, so I couldn't throw my custom exception. After delving into Spring RestTemplate source code, I realized that the code in handleResponseError method is causing the issue - It is looking for response.getStatusCode or response.getStatusText and throwing exception (as statusCode/statusText is null when Rest service throws exception) and it never calls either custom implemented or default handleError method in the next line.

Spring RestTemplate source code for handleResponse method:

private void handleResponseError(HttpMethod method, URI url, ClientHttpResponse response) throws IOException {
    if (logger.isWarnEnabled()) {
        try {
            logger.warn(method.name() + " request for \"" + url + "\" resulted in " +
response.getStatusCode() + " (" + response.getStatusText() + "); invoking error handler");
        }
        catch (IOException e) {
            // ignore
        }
    }
    getErrorHandler().handleError(response);
}

FYI, while service throws exception, I can read rawstatuscode but not statuscode from response

How to bypass this framework code and make call my custom handler? Thanks for your help in advance.

Answer

Abhijeet picture Abhijeet · Nov 17, 2015

Following link has useful information about Exception Flow for Spring ResponseErrorHandler .

Adding code here, just in-case the blog is down:

Code for ErrorHandler:

public class MyResponseErrorHandler implements ResponseErrorHandler {

    private static final Log logger = LogFactory.getLog(MyResponseErrorHandler.class);

    @Override
    public void handleError(ClientHttpResponse clienthttpresponse) throws IOException {

        if (clienthttpresponse.getStatusCode() == HttpStatus.FORBIDDEN) {
            logger.debug(HttpStatus.FORBIDDEN + " response. Throwing authentication exception");
            throw new AuthenticationException();
        }
    }

    @Override
    public boolean hasError(ClientHttpResponse clienthttpresponse) throws IOException {

        if (clienthttpresponse.getStatusCode() != HttpStatus.OK) {
            logger.debug("Status code: " + clienthttpresponse.getStatusCode());
            logger.debug("Response" + clienthttpresponse.getStatusText());
            logger.debug(clienthttpresponse.getBody());

            if (clienthttpresponse.getStatusCode() == HttpStatus.FORBIDDEN) {
                logger.debug("Call returned a error 403 forbidden resposne ");
                return true;
            }
        }
        return false;
    }
}

Code for using it in RestTemplate:

RestTemplate restclient = new RestTemplate();
restclient.setErrorHandler(new MyResponseErrorHandler());
ResponseEntity<String> responseEntity = clientRestTemplate.exchange(
                    URI,
                    HttpMethod.GET,
                    requestEntity,
                    String.class);
                response = responseEntity.getBody();