Getting InputStream with RestTemplate
Spring has a org.springframework.http.converter.ResourceHttpMessageConverter
. It converts Spring's org.springframework.core.io.Resource
class.
That Resource
class encapsulates a InputStream
, which you can obtain via someResource.getInputStream()
.
Putting this all together, you can actually get an InputStream
via RestTemplate
out-of-the-box by specifying Resource.class
as your RestTemplate
invocation's response type.
Here is an example using one of RestTemplate
's exchange(..)
methods:
import org.springframework.web.client.RestTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.core.io.Resource;
ResponseEntity<Resource> responseEntity = restTemplate.exchange( someUrlString, HttpMethod.GET, someHttpEntity, Resource.class );
InputStream responseInputStream;
try {
responseInputStream = responseEntity.getBody().getInputStream();
}
catch (IOException e) {
throw new RuntimeException(e);
}
// use responseInputStream
The previous answers are not wrong, but they don't go into the depth that I like to see. There are cases when dealing with low level InputStream
is not only desirable, but necessary, the most common example being streaming a large file from source (some web server) to destination (a database). If you try to use a ByteArrayInputStream
, you will be, not so surprisingly, greeted with OutOfMemoryError
. Yes, you can roll your own HTTP client code, but you'll have to deal with erroneous response codes, response converters etc. If you are already using Spring, looking to RestTemplate
is a natural choice.
As of this writing, spring-web:5.0.2.RELEASE
has a ResourceHttpMessageConverter
that has a boolean supportsReadStreaming
, which if set, and the response type is InputStreamResource
, returns InputStreamResource
; otherwise it returns a ByteArrayResource
. So clearly, you're not the only one that asked for streaming support.
However, there is a problem: RestTemplate
closes the response soon after the HttpMessageConverter
runs. Thus, even if you asked for InputStreamResource
, and got it, it's no good, because the response stream has been closed. I think this is a design flaw that they overlooked; it should've been dependent on the response type. So unfortunately, for reading, you must consume the response fully; you can't pass it around if using RestTemplate
.
Writing is no problem though. If you want to stream an InputStream
, ResourceHttpMessageConverter
will do it for you. Under the hood, it uses org.springframework.util.StreamUtils
to write 4096 bytes at a time from the InputStream
to the OutputStream
.
Some of the HttpMessageConverter
support all media types, so depending on your requirement, you may have to remove the default ones from RestTemplate
, and set the ones you need, being mindful of their relative ordering.
Last but not the least, implementations of ClientHttpRequestFactory
has a boolean bufferRequestBody
that you can, and should, set to false
if you are uploading a large stream. Otherwise, you know, OutOfMemoryError
. As of this writing, SimpleClientHttpRequestFactory
(JDK client) and HttpComponentsClientHttpRequestFactory
(Apache HTTP client) support this feature, but not OkHttp3ClientHttpRequestFactory
. Again, design oversight.
Edit: Filed ticket SPR-16885.
You should not get the InputStream
directly. RestTemplate
is meant to encapsulate processing the response (and request) content. Its strength is handling all the IO and handing you a ready-to-go Java object.
One of RestTemplate
's original authors, Brian Clozel, has stated:
RestTemplate
is not meant to stream the response body; its contract doesn't allow it, and it's been around for so long that changing such a basic part of its behavior cannot be done without disrupting many applications.
You'll need to register appropriate HttpMessageConverter
objects. Those will have access to the response's InputStream
, through an HttpInputMessage
object.
As Abdull suggests, Spring does come with an HttpMessageConverter
implementation for Resource
which itself wraps an InputStream
, ResourceHttpMessageConverter
. It doesn't support all Resource
types, but since you should be programming to interfaces anyway, you should just use the superinterface Resource
.
The current implementation (4.3.5), will return a ByteArrayResource
with the content of the response stream copied to a new ByteArrayInputStream
which you can access.
You don't have to close the stream. The RestTemplate
takes care of that for you. (This is unfortunate if you try to use a InputStreamResource
, another type supported by the ResourceHttpMessageConverter
, because it wraps the underlying response's InputStream
but is closed before it can be exposed to your client code.)
I encountered the same issue and solved it by extending RestTemplate and closing the connection only after the stream is read.
you can see the code here: https://github.com/ItamarBenjamin/stream-rest-template