Get body from ClientHttpResponse twice

4,394 views
Skip to first unread message

Max Denissov

unread,
Dec 20, 2013, 8:23:29 AM12/20/13
to robo...@googlegroups.com
Hi!

I need to check a response for a business error:


restTemplate.setErrorHandler(new BusinessResponseErrorHandler());


public class BusinessResponseErrorHandler implements ResponseErrorHandler {

    @Override
    public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
        // need to check for error
        String body = IOUtils.toString(clientHttpResponse.getBody());
        return false;
    }


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

    }

}

but I have an error:

org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: No content to map to Object due to end of input; nested exception is java.io.EOFException: No content to map to Object due to end of input

Why Robospice reads the body of a ClientHttpResponse  again ?

Max Denissov

unread,
Dec 20, 2013, 8:32:35 AM12/20/13
to robo...@googlegroups.com
 I found that it called

at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:76)


So, how can I get the response body, without further error?

Stéphane Nicolas

unread,
Jan 3, 2014, 9:45:55 AM1/3/14
to robo...@googlegroups.com
I don't follow you at all Max. Which behavior would you expect ?


--
Vous recevez ce message, car vous êtes abonné au groupe Google Groupes RoboSpice.
Pour vous désabonner de ce groupe et ne plus recevoir d'e-mails le concernant, envoyez un e-mail à l'adresse robospice+...@googlegroups.com.
Pour plus d'options, visitez le site https://groups.google.com/groups/opt_out .



--
Stéphane NICOLAS,
OCTO Technology 
Développeur & Consultant Android / Java
..........................................................
50, Avenue des Champs-Elysées
75008 Paris
+33 (0)6.26.32.34.09
www.octo.com - mobilite.octo.com 
blog.octo.com - www.usievents.com
...........................................................

Max Denissov

unread,
Jan 3, 2014, 9:57:21 AM1/3/14
to robo...@googlegroups.com
Hi! I want to read body of a ClientHttpResponse in ResponseErrorHandler. But if I return 


2014/1/3 Stéphane Nicolas <snic...@octo.com>

--
Vous recevez ce message car vous êtes abonné à un sujet dans le groupe Google Groupes "RoboSpice".
Pour vous désabonner de ce sujet, visitez le site https://groups.google.com/d/topic/robospice/jdsnraa7Nqo/unsubscribe.
Pour vous désabonner de ce groupe et de tous ses sujets, envoyez un e-mail à l'adresse robospice+...@googlegroups.com.

Max Denissov

unread,
Jan 3, 2014, 10:03:20 AM1/3/14
to robospice
Hi! I want to read body of a ClientHttpResponse in ResponseErrorHandler. But if I return  false

public boolean hasError(ClientHttpResponse clientHttpResponse) {
  /// read response body
 ....
 ....
 return false;
}

after that RestTemplate reads body of response and get exception.




2014/1/3 Stéphane Nicolas <snic...@octo.com>

--
Vous recevez ce message car vous êtes abonné à un sujet dans le groupe Google Groupes "RoboSpice".
Pour vous désabonner de ce sujet, visitez le site https://groups.google.com/d/topic/robospice/jdsnraa7Nqo/unsubscribe.
Pour vous désabonner de ce groupe et de tous ses sujets, envoyez un e-mail à l'adresse robospice+...@googlegroups.com.

Stéphane Nicolas

unread,
Jan 3, 2014, 10:09:58 AM1/3/14
to robo...@googlegroups.com
I really need a suggestion from your side, I don't use the retrofit module on a regular basis.


2014/1/3 Max Denissov <max.de...@gmail.com>

Max Denissov

unread,
Jan 3, 2014, 10:16:16 AM1/3/14
to robospice
I created wrapper for response:

public class BufferingClientHttpResponseWrapper implements ClientHttpResponse {

    private final ClientHttpResponse response;

    private byte[] body;


    BufferingClientHttpResponseWrapper(ClientHttpResponse response) {
        this.response = response;
    }


    public HttpStatus getStatusCode() throws IOException {
        return this.response.getStatusCode();
    }

    public int getRawStatusCode() throws IOException {
        return this.response.getRawStatusCode();
    }

    public String getStatusText() throws IOException {
        return this.response.getStatusText();
    }

    public HttpHeaders getHeaders() {
        return this.response.getHeaders();
    }

    public InputStream getBody() throws IOException {
        if (this.body == null) {
            this.body = FileCopyUtils.copyToByteArray(this.response.getBody());
        }
        return new ByteArrayInputStream(this.body);
    }

    public void close() {
        this.response.close();
    }

}



and the class extends from RestTemplate



public class HackRestTemplate extends RestTemplate {

    private static final String TAG = "HackRestTemplate";

    @Override
    protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback,
                              ResponseExtractor<T> responseExtractor) throws RestClientException {

        Assert.notNull(url, "'url' must not be null");
        Assert.notNull(method, "'method' must not be null");
        ClientHttpResponse response = null;
        try {
            ClientHttpRequest request = createRequest(url, method);
            if (requestCallback != null) {
                requestCallback.doWithRequest(request);
            }
            response = wrappResponse(request.execute());
            if (!getErrorHandler().hasError(response)) {
                logResponseStatus(method, url, response);
            }
            else {
                handleResponseError(method, url, response);
            }
            if (responseExtractor != null) {
                return responseExtractor.extractData(response);
            }
            else {
                return null;
            }
        }
        catch (IOException ex) {
            throw new ResourceAccessException("I/O error: " + ex.getMessage(), ex);
        }
        finally {
            if (response != null) {
                response.close();
            }
        }
    }

    private ClientHttpResponse wrappResponse(ClientHttpResponse response) {
        return new BufferingClientHttpResponseWrapper(response);
    }

    private void logResponseStatus(HttpMethod method, URI url, ClientHttpResponse response) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            try {
                Log.d(TAG,
                        method.name() + " request for \"" + url + "\" resulted in " + response.getStatusCode() + " (" +
                                response.getStatusText() + ")");
            }
            catch (IOException e) {
                // ignore
            }
        }
    }

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



Now all work as I want, I can read response body twice, in the ErrorHandler and in the responseExtractor.extractData(response);


Stéphane Nicolas

unread,
Jan 3, 2014, 10:32:24 AM1/3/14
to robo...@googlegroups.com
Hi Max,

I also do stuff like this in my own apps to call some very specific web services. Nevertheless, I doubt anything generic could be added to RS on that matter.

S.


2014/1/3 Max Denissov <max.de...@gmail.com>

Max Denissov

unread,
Jan 3, 2014, 10:36:52 AM1/3/14
to robospice
Ok =) Thank you for the answer.


2014/1/3 Stéphane Nicolas <snic...@octo.com>

Max Denissov

unread,
Jan 18, 2014, 12:11:07 AM1/18/14
to robospice
Hi Stéphane, Why RoboSpice send  three requests when has error? How I can change number of requests?


2014/1/3 Max Denissov <max.de...@gmail.com>

Max Denissov

unread,
Jan 18, 2014, 12:42:55 AM1/18/14
to robospice
О! I found,   public static final int DEFAULT_RETRY_COUNT = 3;


2014/1/18 Max Denissov <max.de...@gmail.com>

Stéphane Nicolas

unread,
Jan 19, 2014, 8:19:26 AM1/19/14
to robo...@googlegroups.com
You got it ! RetryPolicy could also be set to null, if you don't want this.

S.


2014/1/18 Max Denissov <max.de...@gmail.com>

Max Denissov

unread,
Jan 19, 2014, 10:32:52 PM1/19/14
to robospice
I added check on business error into RetryPolicy, if I get it I will not send request again. Thanks.


2014/1/19 Stéphane Nicolas <snic...@octo.com>
Reply all
Reply to author
Forward
0 new messages