Kong / unirest-java

Unirest in Java: Simplified, lightweight HTTP client library.
http://kong.github.io/unirest-java/
MIT License
2.6k stars 594 forks source link

Accessing response body via async callback #303

Closed phillip-odam closed 4 years ago

phillip-odam commented 4 years ago

The bug / problem Perhaps I'm using <T> CompletableFuture<HttpResponse<T>> asObjectAsync(GenericType<T> var1, Callback<T> var2) wrong in some way, for example for the GenericType argument I'm simply providing new GenericType<InputStream>(){}

Short of it is, in the callback the getBody method returns null. Changing over to asBytesAsync on Unirest's get method and the getBody method returns a byte array with the expected content.

Steps to reproduce the behavior:

// My Unirest call
Unirest.get("some url")
       .basicAuth("username", "password")
       .queryString("param1", "value1")
       .queryString("param2", "value2")
       .asObjectAsync(new GenericType<InputStream>(){}, handleRawMessageResponse());

// My Callback method
private Callback<InputStream> handleRawMessageResponse() {
    return new Callback<InputStream>() {
        @Override
        public void completed(HttpResponse<InputStream> httpResponse) {
            System.out.println("completed");
            System.out.println(String.format("HTTP status code: %d", httpResponse.getStatus()));
            for (Header header : httpResponse.getHeaders().all()) {
                System.out.println(String.format("HTTP header %s: %s", header.getName(), header.getValue()));
            }
            // the following will print body inputstream: null
            System.out.println(String.format("body inputstream: %s", httpResponse.getBody()));
        }

        @Override
        public void failed(UnirestException e) {
            System.out.println("failed");
        }

        @Override
        public void cancelled() {
            System.out.println("cancelled");
        }
    };
}

Expected behavior When the GenericType is InputStream, the httpResponse.getBody() should return the input stream.

Environmental Data:

ryber commented 4 years ago

If you look at the response you will find that there was a parsing error and the response could not be mapped to a InputStream. The default ObjectMapper is for JSON responses and well, that's just never going to work.

What this is designed for is mapping from Json to some kind of Pojo. Additionally, the GenericType interface trick is designed for objects with a generic params like List<Foo>. Neither can be used to map into an abstract thing like a InputStream.

If what you want is the original InputStream you can use the thenConsumeAsync method. You must consume the entire InputStream within the Consumer because it will be closed at the end.

If you want the original bytes there is are asBytes methods

phillip-odam commented 4 years ago

Thanks @ryber, probably the lack of exception handling in my IntelliJ scratch file wasn't helping with my understanding of what's going on. I went with the asBytesAsync just like you suggested.

Cheers