diff -r fcb5b835bf32 -r 4f830b447edf src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpResponse.java --- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpResponse.java Thu Dec 21 10:26:03 2017 +0100 +++ b/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpResponse.java Thu Dec 21 16:58:51 2017 +0000 @@ -46,6 +46,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.Flow; +import java.util.concurrent.Flow.Subscriber; import java.util.function.Consumer; import java.util.function.Function; import javax.net.ssl.SSLParameters; @@ -329,6 +330,75 @@ public BodySubscriber apply(int statusCode, HttpHeaders responseHeaders); /** + * Returns a response body handler that returns a {@link BodySubscriber + * BodySubscriber}{@code } obtained from {@linkplain + * BodySubscriber#fromSubscriber(Subscriber)}, with the given + * {@code subscriber}. + * + *

The response body is not available through this, or the {@code + * HttpResponse} API, but instead all response body is forwarded to the + * given {@code subscriber}, which should make it available, if + * appropriate, through some other mechanism, e.g. an entry in a + * database, etc. + * + * @apiNote This method can be used as an adapter between {@code + * BodySubscriber} and {@code Flow.Subscriber}. + * + *

For example: + *

 {@code
+         *  TextSubscriber subscriber = new TextSubscriber();
+         *  HttpResponse response = client.sendAsync(request,
+         *      BodyHandler.fromSubscriber(subscriber)).join();
+         *  System.out.println(response.statusCode());
+         * }
+ * + * @param subscriber the subscriber + * @return a response body handler + */ + public static BodyHandler + fromSubscriber(Subscriber> subscriber) { + Objects.requireNonNull(subscriber); + return (status, headers) -> BodySubscriber.fromSubscriber(subscriber, + s -> null); + } + + /** + * Returns a response body handler that returns a {@link BodySubscriber + * BodySubscriber}{@code } obtained from {@link + * BodySubscriber#fromSubscriber(Subscriber, Function)}, with the + * given {@code subscriber} and {@code finisher} function. + * + *

The given {@code finisher} function is applied after the given + * subscriber's {@code onComplete} has been invoked. The {@code finisher} + * function is invoked with the given subscriber, and returns a value + * that is set as the response's body. + * + * @apiNote This method can be used as an adapter between {@code + * BodySubscriber} and {@code Flow.Subscriber}. + * + *

For example: + *

 {@code
+         * TextSubscriber subscriber = ...;  // accumulates bytes and transforms them into a String
+         * HttpResponse response = client.sendAsync(request,
+         *     BodyHandler.fromSubscriber(subscriber, TextSubscriber::getTextResult)).join();
+         * String text = response.body();
+         * }
+ * + * @param the type of the Subscriber + * @param the type of the response body + * @param subscriber the subscriber + * @param finisher a function to be applied after the subscriber has completed + * @return a response body handler + */ + public static >,T> BodyHandler + fromSubscriber(S subscriber, Function finisher) { + Objects.requireNonNull(subscriber); + Objects.requireNonNull(finisher); + return (status, headers) -> BodySubscriber.fromSubscriber(subscriber, + finisher); + } + + /** * Returns a response body handler which discards the response body and * uses the given value as a replacement for it. * @@ -595,6 +665,53 @@ public CompletionStage getBody(); /** + * Returns a body subscriber that forwards all response body to the + * given {@code Flow.Subscriber}. The {@linkplain #getBody()} completion + * stage} of the returned body subscriber completes after one of the + * given subscribers {@code onComplete} or {@code onError} has been + * invoked. + * + * @apiNote This method can be used as an adapter between {@code + * BodySubscriber} and {@code Flow.Subscriber}. + * + * @param the type of the Subscriber + * @param subscriber the subscriber + * @return a body subscriber + */ + public static >> BodySubscriber + fromSubscriber(S subscriber) { + return new ResponseSubscribers.SubscriberAdapter(subscriber, s -> null); + } + + /** + * Returns a body subscriber that forwards all response body to the + * given {@code Flow.Subscriber}. The {@linkplain #getBody()} completion + * stage} of the returned body subscriber completes after one of the + * given subscribers {@code onComplete} or {@code onError} has been + * invoked. + * + *

The given {@code finisher} function is applied after the given + * subscriber's {@code onComplete} has been invoked. The {@code finisher} + * function is invoked with the given subscriber, and returns a value + * that is set as the response's body. + * + * @apiNote This method can be used as an adapter between {@code + * BodySubscriber} and {@code Flow.Subscriber}. + * + * @param the type of the Subscriber + * @param the type of the response body + * @param subscriber the subscriber + * @param finisher a function to be applied after the subscriber has + * completed + * @return a body subscriber + */ + public static >,T> BodySubscriber + fromSubscriber(S subscriber, + Function finisher) { + return new ResponseSubscribers.SubscriberAdapter(subscriber, finisher); + } + + /** * Returns a body subscriber which stores the response body as a {@code * String} converted using the given {@code Charset}. *