How to forward large files with RestTemplate?

Solution 1:

Edit: The other answers are better (use Resource) https://stackoverflow.com/a/36226006/116509

My original answer:

You can use execute for this kind of low-level operation. In this snippet I've used Commons IO's copy method to copy the input stream. You would need to customize the HttpMessageConverterExtractor for the kind of response you're expecting.

final InputStream fis = new FileInputStream(new File("c:\\autoexec.bat")); // or whatever
final RequestCallback requestCallback = new RequestCallback() {
     @Override
    public void doWithRequest(final ClientHttpRequest request) throws IOException {
        request.getHeaders().add("Content-type", "application/octet-stream");
        IOUtils.copy(fis, request.getBody());
     }
};
final RestTemplate restTemplate = new RestTemplate();
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);     
restTemplate.setRequestFactory(requestFactory);     
final HttpMessageConverterExtractor<String> responseExtractor =
    new HttpMessageConverterExtractor<String>(String.class, restTemplate.getMessageConverters());
restTemplate.execute("http://localhost:4000", HttpMethod.POST, requestCallback, responseExtractor);

(Thanks to Baz for pointing out you need to call setBufferRequestBody(false) or it will defeat the point)

Solution 2:

The only part of @artbristol's answer you really need is this (which you can set up as a RestTemplate Spring bean):

final RestTemplate restTemplate = new RestTemplate();
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);     
restTemplate.setRequestFactory(requestFactory);     

After that, I think just using a FileSystemResource as your request body will do the right thing.

I've also used an InputStreamResource successfully this way, for cases where you already have the data as an InputStream and don't need to consume it multiple times.

In my case, we had gzipped our files and wrapped a GZipInputStream in an InputStreamResource.

Solution 3:

I think that the above answer has unnecessary code - you don't need to make an anonymous RequestCallback inner class, and you don't need to use IOUtils from apache.

I spent a bit of time researching a similar solution to yours and this is what I came up with:

You can accomplish your goal much simpler by using the Spring Resource Interface and RestTemplate.

RestTemplate restTemplate = new RestTemplate();

SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);
restTemplate.setRequestFactory(requestFactory);

File file = new File("/whatever");

HttpEntity<FileSystemResource> requestEntity = new HttpEntity<>(new FileSystemResource(file));
ResponseEntity e = restTemplate.exchange("http://localhost:4000", HttpMethod.POST, requestEntity, Map.class);

(This example assumes that the response from where you are POSTing to is JSON. But, this can easily be changed by changing the return type class... set to Map.class above)