0

My controller method returns InputStreamResource in response body. I'am getting InputStream from the CloseableHttpResponse in the TRY block and I close CloseableHttpResponse in FINALLY block.

The problem is that finally is called before the return and there is no chance to create InputStreamResource from the InputStream because CloseableHttpResponse is already closed.

What could be a possible solution in this case? Can I somehow close CloseableHttpResponse after returning InputStreamResource? I really need to use CloseableHttpClient and the method should return some stream.

    public ResponseEntity<InputStreamResource> getFileAsStream(@PathVariable("uuid") String uuid) throws IOException, InterruptedException {
        CloseableHttpResponse response = fileService.importFileByUuid(uuid);
        try {
            HttpEntity entity = response.getEntity();
            HttpHeaders responseHeaders = new HttpHeaders();
            responseHeaders.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(entity.getContentLength()));
            responseHeaders.add(HttpHeaders.CONTENT_TYPE, entity.getContentType().getValue());
            responseHeaders.add(HttpHeaders.CONTENT_DISPOSITION, response.getFirstHeader(HttpHeaders.CONTENT_DISPOSITION).getValue());

            if (entity != null) {
                InputStream inputStream = entity.getContent();
                InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
                return ResponseEntity.ok()
                            .headers(responseHeaders)
                            .body(inputStreamResource);
            }
            throw new IllegalStateException(String.format(
                    "Error during stream downloading, uuid = %s", uuid));
        } finally {
            response.close();
        }
    } 

1 Answers1

0

You can always create a copy of the InputStream obtained from the HttpEntity and use the copy to create the InputStreamResource that is returned in the ResponseEntity. This way, the original InputStream obtained from the HttpEntity can be safely closed before the ResponseEntity is returned.

InputStream inputStream = entity.getContent();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
IOUtils.copy(inputStream, outputStream);
byte[] contentBytes = outputStream.toByteArray();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(contentBytes);
InputStreamResource inputStreamResource = new InputStreamResource(byteArrayInputStream);

Or save use the byte[] and use it to return ByteArrayResource instead of InputStreamResource

Karim
  • 1,004
  • 8
  • 18
  • Thank you for the answer! Could you make the things clear for me: if I'm downloading a large file which size is 200MB, would this file take up that much space in the application memory with this method? – Evgenia Rubanova Mar 03 '23 at 21:49
  • Yes if that's the case, save the file to the disk using FileOutputStream and use FileSystemResource to send it alternatively you can use UrlResource – Karim Mar 03 '23 at 23:11