Reputation: 2432
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
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