Spring RestTemplate - Overriding ResponseErrorHandler
Asked Answered
I

2

15

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.

Impracticable answered 23/5, 2014 at 21:45 Comment(2)
You can check bellow thread. https://mcmap.net/q/119331/-spring-resttemplate-exception-handlingElectuary
#38093888Sardis
T
17

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();
Thematic answered 17/11, 2015 at 12:16 Comment(1)
This seems like a pretty bad implementation of the hasError() method because it only returns true if the service returns a forbidden error. A much better implementation is one implemented here - https://mcmap.net/q/459253/-spring-resttemplate-invoking-webservice-with-errors-and-analyze-status-codeStockwell
C
4

I don't see your RestTemplate code, but I assume you to set your ResponseErrorHandler for RestTemplate to use like:

RestTemplate restClient = new RestTemplate();
restClient.setErrorHandler(new MyResponseErrorHandler());

The exception is indeed thrown in handleError method. You can find how to throw CustomException using CustomResponseHandler from one of my previous answers.

Castile answered 24/5, 2014 at 2:52 Comment(2)
Nilesh, I tried and it didn't work. To hit custom handleError it should first reach hanldeResponseError() method in RestTempalte and it decides which handleError() it should call but hanldeResponseError() is throwing exception as statuscode is null and it never reach next line. I provided RestTemplate handleResponseError() method code in previous post. FYI, I was trying through spring configuration, now I tried setting manually in code. Either way it didn't workImpracticable
FYI, It is not reaching either custom or default HandleError() to throw CustomException as exception is thrown in caller method handleResponseError() as statuscode is null.Impracticable

© 2022 - 2024 — McMap. All rights reserved.