Nikolas
Nikolas

Reputation: 2432

InputStream is closed in spring controller

Using spring controller, endpoint returns file in the body response. I want to be sure to not to get resource leaks using "try with resources", but in that way in postman I get an error:

"error": "Internal Server Error", "message": "Stream Closed",

snippet of code in Spring controller:

InputStreamResource result;
ResponseEntity<Resource> response;
try(FileInputStream ios = new FileInputStream(file)){
    result = new InputStreamResource(ios);
    response = ResponseEntity.ok()
        .headers(/*some headers here*/)
        .contentLength(file.length())
        .contentType(/*some media type here*/)
        .body(result);
    logger.info("successfully created");
    return response;
} catch (IOException e) {
        //some code here..
}

Interesting, that in logs I got success message, but in postman or in browser (this is a GET request) I got an error.

And it would work, if not to use "try-with-resource", but I'm afraid of resource leaks in that way.

Upvotes: 2

Views: 8195

Answers (1)

LHCHIN
LHCHIN

Reputation: 4009

Because try with resource will call close() before return, a "Stream Closed" error will occur.
A simple way is to directly put the instance of InputStreamResource in .body(), and most examples on web do this as well. However, I am not sure whether the resource will be closed correctly to prevent application from resource leak.

response = ResponseEntity.ok()
    .contentLength(file.length())
    .body(new InputStreamResource(new FileInputStream(file)));
return response;

Another way, if you want to stream the response, you can use StreamingResponseBody.

Interface StreamingResponseBody (quoted from Spring website)

This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

Sample code:

StreamingResponseBody responseBody = outputStream -> {
    Files.copy(file.toPath(), outputStream);
};

response.ok()
    .contentLength(file.length())
    .body(responseBody);
return response;

Upvotes: 6

Related Questions