JEP 321: HTTP Client - Use of Flow.Subscriber and Flow.Publisher

Chris Hegarty chris.hegarty at oracle.com
Fri Dec 8 17:31:55 UTC 2017


James,

Thanks for taking the time to look at this, and sending your thoughts.

On 08/12/17 00:30, James Roper wrote:
 > Hi all,
 >
 > I wanted to start a discussion about the use of Flow.Subscriber and
 > Flow.Publisher in JEP 321 (HTTP Client API).
 >
 > It seems that users are required to implement their own publishers and
 > subscribers, that is, they can't take a Flow.Publisher or
 > Flow.Subscriber provided by another reactive streams implementation, and
 > pass it on to the HttpClient API. The reason for this is that the
 > HttpClient API doesn't accept Flow.Publisher/Flow.Subscriber, rather it
 > extends them in HttpRequest.BodyPublisher and
 > HttpResponse.BodySubscriber, and then requires the user to return
 > instances of those sub interfaces from their BodyHandlers. ...

Great point. I think we can address this with straight forward adapters.
For example:

   public interface BodyPublisher extends Flow.Publisher<ByteBuffer> {

      /**
      * Returns a request body publisher whose body is retrieved from the
      * given {@code Flow.Publisher}. The returned request body publisher
      * has an unknown content length.
      *
      * @apiNote This method can be used as an adapter between {@code
      * BodyPublisher} and {@code Flow.Publisher}.
      *
      * @param publisher the publisher responsible for publishing the body
      * @return a BodyPublisher
      */
     static BodyPublisher fromPublisher(Flow.Publisher<ByteBuffer> 
publisher) {
         ...
     }

     ...

    public BodySubscriber<T> apply(int statusCode, HttpHeaders 
responseHeaders);

      /**
       * Returns a response body handler that returns a {@link 
BodySubscriber
       * BodySubscriber}{@code <Void>} obtained from {@link
       * BodySubscriber#fromSubscriber(Subscriber)}.
       *
       * @apiNote This method can be used as an adapter between {@code
       * BodySubscriber} and {@code Flow.Subscriber}.
       *
       * <p> For example:
       * <pre> {@code
       * TextSubscriber subscriber = ...;  // accumulates bytes and 
transforms them into a String.
       * Supplier<String> result = subscriber::getTextResult;
       *
       * CompletableFuture<String> cf =  client
       *         .sendAsync(request, BodyHandler.fromSubscriber(subscriber))
       *         .thenApply((response -> result.get()));
       * String text = cf.join();
       * }</pre>
       *
       * @param subscriber the subscriber
       * @return a response body handler
       */
      public static BodyHandler<Void> fromSubscriber(Subscriber<? super 
List<ByteBuffer>> subscriber) {
          ...
      }

      // Add an equivalent BodySubscriber ...


This would allow the API to retain its Flow specific types ( that add
additional HTTP specific and API behavior ), while interacting, without
much fuss, with regular Publishers and Subscribers.

-Chris.


More information about the net-dev mailing list