From 4e2fb308f6516cc8e2617ecef195dccdbb680ed9 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 24 Jun 2024 12:10:35 +0200 Subject: [PATCH] Document contentLength() behavior for InputStreamResource and custom subclasses Closes gh-33089 --- .../mvc-controller/ann-methods/responseentity.adoc | 4 +++- .../springframework/core/io/InputStreamResource.java | 11 +++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/responseentity.adoc b/framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/responseentity.adoc index 2baae5ae767..218ac995399 100644 --- a/framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/responseentity.adoc +++ b/framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/responseentity.adoc @@ -40,7 +40,9 @@ content of the provided resource to the response `OutputStream`. Note that the `InputStream` should be lazily retrieved by the `Resource` handle in order to reliably close it after it has been copied to the response. If you are using `InputStreamResource` for such a purpose, make sure to construct it with an on-demand `InputStreamSource` -(e.g. through a lambda expression that retrieves the actual `InputStream`). +(e.g. through a lambda expression that retrieves the actual `InputStream`). Also, custom +subclasses of `InputStreamResource` are only supported in combination with a custom +`contentLength()` implementation which avoids consuming the stream for that purpose. Spring MVC supports using a single value xref:web/webmvc/mvc-ann-async.adoc#mvc-ann-async-reactive-types[reactive type] to produce the `ResponseEntity` asynchronously, and/or single and multi-value reactive diff --git a/spring-core/src/main/java/org/springframework/core/io/InputStreamResource.java b/spring-core/src/main/java/org/springframework/core/io/InputStreamResource.java index 0615134e9e9..906eb233a6c 100644 --- a/spring-core/src/main/java/org/springframework/core/io/InputStreamResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/InputStreamResource.java @@ -40,6 +40,13 @@ import org.springframework.util.Assert; * times. This also applies when constructed with an {@code InputStreamSource} * which lazily obtains the stream but only allows for single access as well. * + *

NOTE: This class does not provide an independent {@link #contentLength()} + * implementation: Any such call will consume the given {@code InputStream}! + * Consider overriding {@code #contentLength()} with a custom implementation if + * possible. For any other purpose, it is not recommended to extend from this + * class; this is particularly true when used with Spring's web resource rendering + * which specifically skips {@code #contentLength()} for this exact class only. + * * @author Juergen Hoeller * @author Sam Brannen * @since 28.12.2003 @@ -132,8 +139,8 @@ public class InputStreamResource extends AbstractResource { @Override public InputStream getInputStream() throws IOException, IllegalStateException { if (this.read) { - throw new IllegalStateException("InputStream has already been read - " + - "do not use InputStreamResource if a stream needs to be read multiple times"); + throw new IllegalStateException("InputStream has already been read (possibly for early content length " + + "determination) - do not use InputStreamResource if a stream needs to be read multiple times"); } this.read = true; return this.inputStreamSource.getInputStream();