Skip to content

Commit 3cb498f

Browse files
committed
Improve docs on streaming via StreamingHttpOutputMessage
Closes spring-projectsgh-35700
1 parent 335a2c4 commit 3cb498f

File tree

3 files changed

+45
-11
lines changed

3 files changed

+45
-11
lines changed

spring-web/src/main/java/org/springframework/http/StreamingHttpOutputMessage.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,34 @@
2020
import java.io.OutputStream;
2121

2222
/**
23-
* Represents an HTTP output message that allows for setting a streaming body.
24-
* Note that such messages typically do not support {@link #getBody()} access.
23+
* Contract for {@code HttpOutputMessage} implementations to expose the ability
24+
* to stream request body content by writing to an {@link OutputStream} from
25+
* a callback.
26+
*
27+
* <p>The {@link #setBody(Body)} method provides the option to stream, and is
28+
* mutually exclusive use of {@link #getBody()}, which instead returns an
29+
* {@code OutputStream} that aggregates the request body before sending it.
2530
*
2631
* @author Arjen Poutsma
32+
* @author Rossen Stoyanchev
2733
* @since 4.0
2834
* @see #setBody
2935
*/
3036
public interface StreamingHttpOutputMessage extends HttpOutputMessage {
3137

3238
/**
3339
* Set the streaming body callback for this message.
40+
* <p>Note that this is mutually exclusive with {@link #getBody()}, which
41+
* may instead aggregate the request body before sending it.
3442
* @param body the streaming body callback
3543
*/
3644
void setBody(Body body);
3745

3846

3947
/**
40-
* Defines the contract for bodies that can be written directly to an
41-
* {@link OutputStream}. Useful with HTTP client libraries that provide
42-
* indirect access to an {@link OutputStream} via a callback mechanism.
48+
* Contract to stream request body content to an {@link OutputStream}.
49+
* In some HTTP client libraries this is only possible indirectly through a
50+
* callback mechanism.
4351
*/
4452
@FunctionalInterface
4553
interface Body {

spring-web/src/main/java/org/springframework/http/client/AbstractStreamingClientHttpRequest.java

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,24 @@
2020
import java.io.OutputStream;
2121

2222
import org.springframework.http.HttpHeaders;
23+
import org.springframework.http.HttpOutputMessage;
2324
import org.springframework.http.StreamingHttpOutputMessage;
2425
import org.springframework.lang.Nullable;
2526
import org.springframework.util.Assert;
2627
import org.springframework.util.FastByteArrayOutputStream;
2728

2829
/**
29-
* Abstract base for {@link ClientHttpRequest} that also implement
30-
* {@link StreamingHttpOutputMessage}. Ensures that headers and
31-
* body are not written multiple times.
30+
* Extension of {@link AbstractClientHttpRequest} that adds the ability to stream
31+
* request body content directly to the underlying HTTP client library through
32+
* the {@link StreamingHttpOutputMessage} contract.
33+
*
34+
* <p>It is necessary to call {@link #setBody} and stream the request body through
35+
* a callback for access to the {@code OutputStream}. The alternative to call
36+
* {@link #getBody()} is also supported as a fallback, but that does not stream,
37+
* and returns an aggregating {@code OutputStream} instead.
3238
*
3339
* @author Arjen Poutsma
40+
* @author Rossen Stoyanchev
3441
* @since 6.1
3542
*/
3643
abstract class AbstractStreamingClientHttpRequest extends AbstractClientHttpRequest
@@ -43,6 +50,12 @@ abstract class AbstractStreamingClientHttpRequest extends AbstractClientHttpRequ
4350
private FastByteArrayOutputStream bodyStream;
4451

4552

53+
/**
54+
* Implements the {@link HttpOutputMessage} contract for request body content.
55+
* <p>Note that this method does not result in streaming, and the returned
56+
* {@code OutputStream} aggregates the full content in a byte[] before
57+
* sending. To use streaming, call {@link #setBody} instead.
58+
*/
4659
@Override
4760
protected final OutputStream getBodyInternal(HttpHeaders headers) {
4861
Assert.state(this.body == null, "Invoke either getBody or setBody; not both");
@@ -53,6 +66,10 @@ protected final OutputStream getBodyInternal(HttpHeaders headers) {
5366
return this.bodyStream;
5467
}
5568

69+
/**
70+
* Implements the {@link StreamingHttpOutputMessage} contract for writing
71+
* request body by streaming directly to the underlying HTTP client.
72+
*/
5673
@Override
5774
public final void setBody(Body body) {
5875
Assert.notNull(body, "Body must not be null");
@@ -73,12 +90,14 @@ protected final ClientHttpResponse executeInternal(HttpHeaders headers) throws I
7390

7491

7592
/**
76-
* Abstract template method that writes the given headers and content to the HTTP request.
77-
* @param headers the HTTP headers
93+
* Abstract method for concrete implementations to write the headers and
94+
* {@link StreamingHttpOutputMessage.Body} to the HTTP request.
95+
* @param headers the HTTP headers for the request
7896
* @param body the HTTP body, may be {@code null} if no body was {@linkplain #setBody(Body) set}
7997
* @return the response object for the executed request
8098
* @since 6.1
8199
*/
82-
protected abstract ClientHttpResponse executeInternal(HttpHeaders headers, @Nullable Body body) throws IOException;
100+
protected abstract ClientHttpResponse executeInternal(
101+
HttpHeaders headers, @Nullable Body body) throws IOException;
83102

84103
}

spring-web/src/main/java/org/springframework/web/client/RequestCallback.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.IOException;
2020
import java.lang.reflect.Type;
2121

22+
import org.springframework.http.HttpOutputMessage;
2223
import org.springframework.http.client.ClientHttpRequest;
2324

2425
/**
@@ -44,6 +45,12 @@ public interface RequestCallback {
4445
* Gets called by {@link RestTemplate#execute} with an opened {@code ClientHttpRequest}.
4546
* Does not need to care about closing the request or about handling errors:
4647
* this will all be handled by the {@code RestTemplate}.
48+
* <p><strong>Note:</strong> In order to stream request body content directly
49+
* to the underlying HTTP library, implementations must check if the request
50+
* is an implementation of {@link org.springframework.http.StreamingHttpOutputMessage},
51+
* and set the request body through it. Use of the {@link HttpOutputMessage#getBody()}
52+
* is also supported, but results in full content aggregation prior to execution.
53+
* All built-in request implementations support {@code StreamingHttpOutputMessage}.
4754
* @param request the active HTTP request
4855
* @throws IOException in case of I/O errors
4956
*/

0 commit comments

Comments
 (0)