# HG changeset patch # User chegar # Date 1518123515 0 # Node ID 15dc43936d39f64cbd88e600aa84c6d2d3694560 # Parent 881f0ecb513f91bc5a3f3735198bc0ed079603e7 http-client-branch: javadoc refresh and minor fixes diff -r 881f0ecb513f -r 15dc43936d39 make/common/Modules.gmk --- a/make/common/Modules.gmk Wed Feb 07 22:49:25 2018 +0000 +++ b/make/common/Modules.gmk Thu Feb 08 20:58:35 2018 +0000 @@ -143,7 +143,7 @@ # DOCS_MODULES defines the root modules for javadoc generation. # All of their `require transitive` modules directly and indirectly will be included. DOCS_MODULES += \ - java.net.http\ + java.net.http \ java.se.ee \ java.smartcardio \ jdk.accessibility \ diff -r 881f0ecb513f -r 15dc43936d39 src/java.net.http/share/classes/java/net/http/HttpClient.java --- a/src/java.net.http/share/classes/java/net/http/HttpClient.java Wed Feb 07 22:49:25 2018 +0000 +++ b/src/java.net.http/share/classes/java/net/http/HttpClient.java Thu Feb 08 20:58:35 2018 +0000 @@ -31,6 +31,9 @@ import java.net.InetSocketAddress; import java.net.Proxy; import java.net.ProxySelector; +import java.net.URLPermission; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -45,37 +48,81 @@ /** * An HTTP Client. * - *

An {@code HttpClient} can be used to send requests and retrieve their - * responses. An {@code HttpClient} is created through a {@link - * HttpClient#newBuilder() builder}. The builder can be used to configure - * per-client state, like: the preferred protocol version ( HTTP/1.1 or HTTP/2 ), - * whether to follow redirects, a proxy, an authenticator, etc. Once built, an - * {@code HttpClient} is immutable, and can be used to send multiple requests. + *

An {@code HttpClient} can be used to send {@linkplain HttpRequest + * requests} and retrieve their {@linkplain HttpResponse responses}. An {@code + * HttpClient} is created through a {@link HttpClient#newBuilder() builder}. The + * builder can be used to configure per-client state, like: the preferred + * protocol version ( HTTP/1.1 or HTTP/2 ), whether to follow redirects, a + * proxy, an authenticator, etc. Once built, an {@code HttpClient} is immutable, + * and can be used to send multiple requests. * *

An {@code HttpClient} provides configuration information, and resource * sharing, for all requests send through it. * - *

For Example: + *

Requests can be made either synchronously or asynchronously: + *

+ * + *

A {@linkplain BodyHandler BodyHandler} must be supplied for each {@code + * HttpRequest} sent. The {@code BodyHandler} determines how to handle the + * response body, if any. Once an {@linkplain HttpResponse} is received, the + * headers, response code, and body (typically) are available. Whether the + * response body bytes has been read or not depends on the type {@code } of + * the response body. + * + *

Synchronous Example *

{@code    HttpClient client = HttpClient.newBuilder()
- *        .version(Version.HTTP_2)
+ *        .version(Version.HTTP_1)
  *        .followRedirects(Redirect.SAME_PROTOCOL)
- *        .proxy(ProxySelector.of(new InetSocketAddress("proxy.com", 8080)))
+ *        .proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
  *        .authenticator(Authenticator.getDefault())
  *        .build();
+ *   HttpResponse response = client.send(request, BodyHandler.asString());
+ *   System.out.println(response.statusCode());
+ *   System.out.println(response.body());  }
* - * HttpRequest request = HttpRequest.newBuilder() - * .uri(URI.create("http://foo.com/")) + *

Asynchronous Example + *

{@code    HttpRequest request = HttpRequest.newBuilder()
+ *        .uri(URI.create("https://foo.com/"))
  *        .timeout(Duration.ofMinutes(1))
  *        .header("Content-Type", "application/json")
  *        .POST(BodyPublisher.fromFile(Paths.get("file.json")))
  *        .build();
- *
  *   client.sendAsync(request, BodyHandler.asString())
  *        .thenApply(HttpResponse::body)
  *        .thenAccept(System.out::println)
  *        .join();  }
* - *

See {@link HttpRequest} for further examples of usage of this API. + *

Security checks + * + *

If a security manager is present then security checks are performed by + * the HTTP Client's sending methods. An appropriate {@link URLPermission} is + * required to access the destination server, and proxy server if one has + * been configured. The form of the {@code URLPermission} required to access a + * proxy has a {@code method} parameter of {@code "CONNECT"} (for all kinds of + * proxying) and a {@code URL} string of the form {@code "socket://host:port"} + * where host and port specify the proxy's address. + * + * @implNote If an explicit {@linkplain HttpClient.Builder#executor(Executor) + * executor} has not been set for an {@code HttpClient}, and a security manager + * has been installed, then the default executor will execute asynchronous and + * dependent tasks in a context that is granted no permissions. Custom + * {@linkplain HttpRequest.BodyPublisher request body publishers}, {@linkplain + * HttpResponse.BodyHandler response body handlers}, {@linkplain + * HttpResponse.BodySubscriber response body subscribers}, and {@linkplain + * WebSocket.Listener WebSocket Listeners}, if executing operations that require + * privileges, should do so within an appropriate {@linkplain + * AccessController#doPrivileged(PrivilegedAction) privileged context}. * * @since 11 */ @@ -87,7 +134,7 @@ protected HttpClient() {} /** - * Returns a new HttpClient with default settings. + * Returns a new {@code HttpClient} with default settings. * *

Equivalent to {@code newBuilder().build()}. * @@ -113,14 +160,14 @@ /** * Creates a new {@code HttpClient} builder. * - * @return a {@code HttpClient.Builder} + * @return an {@code HttpClient.Builder} */ public static Builder newBuilder() { return new HttpClientBuilderImpl(); } /** - * A builder of immutable {@link HttpClient}s. + * A builder of {@link HttpClient}s. * *

Builders are created by invoking {@linkplain HttpClient#newBuilder() * newBuilder}. Each of the setter methods modifies the state of the builder @@ -254,20 +301,20 @@ /** * Sets a {@link java.net.ProxySelector}. * - * @apiNote {@link ProxySelector#of(InetSocketAddress)} + * @apiNote {@link ProxySelector#of(InetSocketAddress) ProxySelector::of} * provides a {@code ProxySelector} which uses a single proxy for all * requests. The system-wide proxy selector can be retrieved by * {@link ProxySelector#getDefault()}. * * @implNote - * If this method is not invoked prior to {@linkplain #build() - * building}, then newly built clients will use the {@linkplain - * ProxySelector#getDefault() default proxy selector}, which - * is normally adequate for client applications. This default - * behavior can be turned off by supplying an explicit proxy - * selector to this method, such as {@link #NO_PROXY} or one - * returned by {@link ProxySelector#of(InetSocketAddress)}, - * before calling {@link #build()}. + * If this method is not invoked prior to {@linkplain #build() building}, + * then newly built clients will use the {@linkplain + * ProxySelector#getDefault() default proxy selector}, which is usually + * adequate for client applications. This default behavior can be turned + * off by supplying an explicit proxy selector to this method, such as + * {@link #NO_PROXY} or one returned by {@linkplain + * ProxySelector#of(InetSocketAddress) ProxySelector::of}, before + * {@linkplain #build() building}. * * @param selector the ProxySelector * @return this builder @@ -442,27 +489,27 @@ * handler ). * * @param the response body type - * @param req the request + * @param request the request * @param responseBodyHandler the response body handler - * @return the response body + * @return the response * @throws IOException if an I/O error occurs when sending or receiving * @throws InterruptedException if the operation is interrupted * @throws IllegalArgumentException if the request method is not supported * @throws SecurityException If a security manager has been installed * and it denies {@link java.net.URLPermission access} to the * URL in the given request, or proxy if one is configured. - * See HttpRequest for further information about - * security checks. + * See security checks for further + * information. */ public abstract HttpResponse - send(HttpRequest req, HttpResponse.BodyHandler responseBodyHandler) + send(HttpRequest request, HttpResponse.BodyHandler responseBodyHandler) throws IOException, InterruptedException; /** - * Sends the given request asynchronously using this client and the given - * response handler. + * Sends the given request asynchronously using this client with the given + * response body handler. * - *

Equivalent to {@code sendAsync(request, responseBodyHandler, null)}. + *

Equivalent to: {@code sendAsync(request, responseBodyHandler, null)}. * * @param the response body type * @param request the request @@ -492,8 +539,8 @@ *

  • {@link SecurityException} - If a security manager has been installed * and it denies {@link java.net.URLPermission access} to the * URL in the given request, or proxy if one is configured. - * See HttpRequest for further information about - * security checks.
  • + * See security checks for further + * information. * * * @param the response body type @@ -511,24 +558,20 @@ * Creates a new {@code WebSocket} builder (optional operation). * *

    Example - *

    {@code
    -     *     HttpClient client = HttpClient.newHttpClient();
    +     * 
    {@code      HttpClient client = HttpClient.newHttpClient();
          *     CompletableFuture ws = client.newWebSocketBuilder()
    -     *             .buildAsync(URI.create("ws://websocket.example.com"), listener);
    -     * }
    + * .buildAsync(URI.create("ws://websocket.example.com"), listener); }
    * *

    Finer control over the WebSocket Opening Handshake can be achieved * by using a custom {@code HttpClient}. * *

    Example - *

    {@code
    -     *     InetSocketAddress addr = new InetSocketAddress("proxy.example.com", 80);
    +     * 
    {@code      InetSocketAddress addr = new InetSocketAddress("proxy.example.com", 80);
          *     HttpClient client = HttpClient.newBuilder()
          *             .proxy(ProxySelector.of(addr))
          *             .build();
          *     CompletableFuture ws = client.newWebSocketBuilder()
    -     *             .buildAsync(URI.create("ws://websocket.example.com"), listener);
    -     * }
    + * .buildAsync(URI.create("ws://websocket.example.com"), listener); }
    * *

    A {@code WebSocket.Builder} returned from this method is not safe for * use by multiple threads without external synchronization. diff -r 881f0ecb513f -r 15dc43936d39 src/java.net.http/share/classes/java/net/http/HttpRequest.java --- a/src/java.net.http/share/classes/java/net/http/HttpRequest.java Wed Feb 07 22:49:25 2018 +0000 +++ b/src/java.net.http/share/classes/java/net/http/HttpRequest.java Thu Feb 08 20:58:35 2018 +0000 @@ -52,60 +52,33 @@ /** * An HTTP request. * - *

    An {@code HttpRequest} instance is built through a {@code HttpRequest} + *

    An {@code HttpRequest} instance is built through an {@code HttpRequest} * {@linkplain HttpRequest.Builder builder}. An {@code HttpRequest} builder - * is obtained from one of the {@link HttpRequest#newBuilder(URI) newBuilder} + * is obtained from one of the {@linkplain HttpRequest#newBuilder(URI) newBuilder} * methods. A request's {@linkplain URI}, headers, and body can be set. Request - * bodies are provided through a {@link BodyPublisher} object supplied to the - * {@link Builder#DELETE(BodyPublisher) DELETE}, - * {@link Builder#POST(BodyPublisher) POST} or - * {@link Builder#PUT(BodyPublisher) PUT} methods. + * bodies are provided through a {@linkplain BodyPublisher BodyPublisher} + * supplied to one of the {@linkplain Builder#DELETE(BodyPublisher) DELETE}, + * {@linkplain Builder#POST(BodyPublisher) POST} or + * {@linkplain Builder#PUT(BodyPublisher) PUT} methods. * Once all required parameters have been set in the builder, {@link * Builder#build() build} will return the {@code HttpRequest}. Builders can be * copied and modified many times in order to build multiple related requests * that differ in some parameters. * - *

    Example HTTP interactions: - *

    {@code    // GET
    - *    HttpResponse response = client.send(
    - *          HttpRequest.newBuilder(new URI("http://www.foo.com/"))
    - *                     .headers("Foo", "foovalue", "Bar", "barvalue")
    - *                     .GET()
    - *                     .build(),
    - *          BodyHandler.asString()
    - *    );
    - *    int statusCode = response.statusCode();
    - *    String body = response.body();
    + * 

    Example: GET request that prints the response body as a String + *

    {@code    HttpClient client = HttpClient.newHttpClient();
    + *   HttpRequest request = HttpRequest.newBuilder()
    + *         .uri(URI.create("http://foo.com/"))
    + *         .build();
    + *   client.sendAsync(request, BodyHandler.asString())
    + *         .thenApply(HttpResponse::body)
    + *         .thenAccept(System.out::println)
    + *         .join(); }
    * - * // POST - * HttpResponse response = client.send( - * HttpRequest.newBuilder(new URI("http://www.foo.com/")) - * .headers("Foo", "foovalue", "Bar", "barvalue") - * .POST(BodyPublisher.fromString("Hello world")) - * .build(), - * BodyHandler.asFile(Paths.get("/path")) - * ); - * int statusCode = response.statusCode(); - * Path body = response.body(); // should be "/path" }
    - * - *

    The request is sent and the response obtained by invoking one of the - * following methods in {@link HttpClient}. - *

    - * - *

    Once a {@link HttpResponse} is received, the headers, response code, - * and body (typically) are available. Whether the response body bytes has been - * read or not depends on the type {@code } of the response body. See below. - * - *

    Request bodies + *

    Request bodies * *

    Request bodies can be sent using one of the convenience request publisher - * implementations, provided in {@link BodyPublisher}. Alternatively, a custom - * Publisher implementation can be used. + * implementations, provided in {@linkplain BodyPublisher BodyPublisher}. *

    * - *

    Response bodies - * - *

    Responses bodies are handled at two levels. When sending the request, - * a response {@linkplain BodyHandler body handler} is specified. This is a - * function that will be called with the response status code and headers, once - * they are received. This function must to return a {@link - * HttpResponse.BodySubscriber}{@code } which is used to read the response - * body bytes, converting them into an instance of {@code T}. After this occurs, - * the response becomes available in a {@link HttpResponse}, and the {@link - * HttpResponse#body()} can be invoked to obtain the actual body. Some - * implementations and examples of usage of both {@link - * HttpResponse.BodySubscriber} and {@link HttpResponse.BodyHandler} are - * provided in {@link HttpResponse}: - * - *

    Some of the pre-defined body handlers
    - *

    - * - *

    Blocking/asynchronous behavior and thread usage - * - *

    There are two styles of request sending: synchronous and - * asynchronous. {@link HttpClient#send(HttpRequest, HttpResponse.BodyHandler) } - * blocks the calling thread until the request has been sent and the response received. - * - *

    {@link HttpClient#sendAsync(HttpRequest, HttpResponse.BodyHandler)} is - * asynchronous and returns immediately with a {@link CompletableFuture}<{@link - * HttpResponse}> and when this object completes (possibly in a different - * thread) the response has been received. - * - *

    Instances of {@code CompletableFuture} can be combined in different ways - * to declare the dependencies among several asynchronous tasks, while allowing - * for the maximum level of parallelism to be utilized. - * - *

    Security checks - * - *

    If a security manager is present then security checks are performed by - * the HTTP Client's sending methods. An appropriate {@link URLPermission} is - * required to access the destination server, and proxy server if one has - * been configured. The {@code URLPermission} form used to access proxies uses a - * method parameter of {@code "CONNECT"} (for all kinds of proxying) and a URL - * string of the form {@code "socket://host:port"} where host and port specify - * the proxy's address. - * - *

    In this implementation, if an explicit {@linkplain - * HttpClient.Builder#executor(Executor) executor} has not been set for an - * {@code HttpClient}, and a security manager has been installed, then the - * default executor will execute asynchronous and dependent tasks in a context - * that is granted no permissions. Custom {@linkplain HttpRequest.BodyPublisher - * request body publishers}, {@linkplain HttpResponse.BodyHandler response body - * handlers}, {@linkplain HttpResponse.BodySubscriber response body subscribers}, - * and {@linkplain WebSocket.Listener WebSocket Listeners}, if executing - * operations that require privileges, should do so within an appropriate - * {@linkplain AccessController#doPrivileged(PrivilegedAction) privileged context}. - * - *

    Examples - *

    {@code    HttpClient client = HttpClient.newHttpClient();
    - *
    - *    HttpRequest request = HttpRequest
    - *            .newBuilder(URI.create("http://www.foo.com/"))
    - *            .POST(BodyPublisher.fromString("Hello world"))
    - *            .build();
    - *
    - *    HttpResponse response =
    - *        client.send(request, BodyHandler.asFile(Paths.get("/path")));
    - *
    - *    Path body = response.body(); }
    - * - *

    Asynchronous Example - * - *

    The above example will work asynchronously, if {@link HttpClient#sendAsync - * (HttpRequest, HttpResponse.BodyHandler) sendAsync} is used instead of - * {@link HttpClient#send(HttpRequest,HttpResponse.BodyHandler) send} - * in which case the returned object is a {@link CompletableFuture}{@code } - * instead of {@link HttpResponse}. The following example shows how multiple requests - * can be sent asynchronously. It also shows how dependent asynchronous operations - * (receiving response, and receiving response body) can be chained easily using - * one of the many methods in {@code CompletableFuture}. - *

    {@code     // fetch a list of target URIs asynchronously and store them in Files.
    - *
    - *    List targets = ...
    - *
    - *    List> futures = targets
    - *        .stream()
    - *        .map(target -> client
    - *                .sendAsync(
    - *                    HttpRequest.newBuilder(target)
    - *                               .GET()
    - *                               .build(),
    - *                    BodyHandler.asFile(Paths.get("base", target.getPath())))
    - *                .thenApply(response -> response.body())
    - *                .thenApply(path -> path.toFile()))
    - *        .collect(Collectors.toList());
    - *
    - *    // all async operations waited for here
    - *
    - *    CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
    - *        .join();
    - *
    - *    // all elements of futures have completed and can be examined.
    - *    // Use File.exists() to check whether file was successfully downloaded }
    + *

    Alternatively, a custom {@code BodyPublisher} implementation can be used. * * @since 11 */ @@ -237,7 +103,7 @@ protected HttpRequest() {} /** - * A builder of {@linkplain HttpRequest HTTP Requests}. + * A builder of {@linkplain HttpRequest HTTP requests}. * *

    Instances of {@code HttpRequest.Builder} are created by calling {@link * HttpRequest#newBuilder(URI)} or {@link HttpRequest#newBuilder()}. @@ -245,16 +111,15 @@ *

    Each of the setter methods in this class modifies the state of the * builder and returns this (ie. the same instance). The methods are * not synchronized and should not be called from multiple threads without - * external synchronization. + * external synchronization. The {@linkplain #build() build} method returns + * a new {@code HttpRequest} each time it is invoked. Once built an {@code + * HttpRequest} is immutable, and can be sent multiple times. * *

    Note, that not all request headers may be set by user code. Some are * restricted for security reasons and others such as the headers relating - * to authentication, redirection and cookie management are managed by + * to authentication, redirection and cookie management may be managed by * specific APIs rather than through directly user set headers. * - *

    The {@linkplain #build() build} method returns a new {@code - * HttpRequest} each time it is invoked. - * * @since 11 */ public abstract static class Builder { @@ -447,7 +312,7 @@ } /** - * Creates a {@code HttpRequest} builder. + * Creates an {@code HttpRequest} builder with the given URI. * * @param uri the request URI * @return a new request builder @@ -458,7 +323,7 @@ } /** - * Creates a {@code HttpRequest} builder. + * Creates an {@code HttpRequest} builder. * * @return a new request builder */ @@ -493,15 +358,15 @@ public abstract Optional timeout(); /** - * Returns this request's {@link HttpRequest.Builder#expectContinue(boolean) - * expect continue } setting. + * Returns this request's {@linkplain HttpRequest.Builder#expectContinue(boolean) + * expect continue} setting. * * @return this request's expect continue setting */ public abstract boolean expectContinue(); /** - * Returns this request's request {@code URI}. + * Returns this request's {@code URI}. * * @return this request's URI */ @@ -571,31 +436,31 @@ } /** - * A Publisher which converts high level Java objects into flows of - * byte buffers suitable for sending as request bodies. + * A {@code BodyPublisher} converts high-level Java objects into a flow of + * byte buffers suitable for sending as a request body. * - *

    The {@code BodyPublisher} class implements {@link Flow.Publisher - * Flow.Publisher<ByteBuffer>} which means that a {@code BodyPublisher} + *

    The {@code BodyPublisher} interface extends {@link Flow.Publisher + * Flow.Publisher<ByteBuffer>}, which means that a {@code BodyPublisher} * acts as a publisher of {@linkplain ByteBuffer byte buffers}. * - *

    The HTTP client implementation subscribes to the publisher in order - * to receive the flow of outgoing data buffers. The normal semantics of - * {@link Flow.Subscriber} and {@link Flow.Publisher} are implemented by the - * library and are expected from publisher implementations. Each outgoing - * request results in one {@code Subscriber} subscribing to the {@code - * BodyPublisher} in order to provide the sequence of byte buffers - * containing the request body. - * Instances of {@code ByteBuffer} published by the publisher must be - * allocated by the publisher, and must not be accessed after being handed - * over to the library. - * These subscriptions complete normally when the request is fully sent, - * and can be canceled or terminated early through error. If a request - * needs to be resent for any reason, then a new subscription is created - * which is expected to generate the same data as before. + *

    When sending a request that contains a body, the HTTP Client + * subscribes to the request's {@code BodyPublisher} in order to receive the + * flow of outgoing request body data. The normal semantics of {@link + * Flow.Subscriber} and {@link Flow.Publisher} are implemented by the HTTP + * Client and are expected from {@code BodyPublisher} implementations. Each + * outgoing request results in one HTTP Client {@code Subscriber} + * subscribing to the {@code BodyPublisher} in order to provide the sequence + * of byte buffers containing the request body. Instances of {@code + * ByteBuffer} published by the publisher must be allocated by the + * publisher, and must not be accessed after being published to the HTTP + * Client. These subscriptions complete normally when the request body is + * fully sent, and can be canceled or terminated early through error. If a + * request needs to be resent for any reason, then a new subscription is + * created which is expected to generate the same data as before. * - *

    A publisher that reports a {@linkplain #contentLength() content - * length} of {@code 0} may not be subscribed to by the HTTP client - * implementation, as it has effectively no data to publish. + *

    A {@code BodyPublisher} that reports a {@linkplain #contentLength() + * content length} of {@code 0} may not be subscribed to by the HTTP Client, + * as it has effectively no data to publish. */ public interface BodyPublisher extends Flow.Publisher { diff -r 881f0ecb513f -r 15dc43936d39 src/java.net.http/share/classes/java/net/http/HttpResponse.java --- a/src/java.net.http/share/classes/java/net/http/HttpResponse.java Wed Feb 07 22:49:25 2018 +0000 +++ b/src/java.net.http/share/classes/java/net/http/HttpResponse.java Thu Feb 08 20:58:35 2018 +0000 @@ -57,37 +57,22 @@ import static jdk.internal.net.http.common.Utils.charsetFrom; /** - * Represents a response to a {@link HttpRequest}. - * - *

    A {@code HttpResponse} is available when the response status code and - * headers have been received, and typically after the response body has also - * been received. This depends on the response body handler provided when - * sending the request. In all cases, the response body handler is invoked - * before the body is read. This gives applications an opportunity to decide - * how to handle the body. - * - *

    Methods are provided in this class for accessing the response headers, - * and response body. - * - *

    Response handlers and subscribers + * An HTTP response. * - *

    Response bodies are handled at two levels. Application code supplies a - * response handler ({@link BodyHandler}) which may examine the response status - * code and headers, and which then returns a {@link BodySubscriber} to actually - * read (or discard) the body and convert it into some useful Java object type. - * The handler can return one of the pre-defined subscriber types, or a custom - * subscriber, or if the body is to be discarded it can call {@link - * BodySubscriber#discard() discard} and return a subscriber which - * discards the response body. Static implementations of both handlers and - * subscribers are provided in {@linkplain BodyHandler BodyHandler} and - * {@linkplain BodySubscriber BodySubscriber} respectively. In all cases, the - * handler functions provided are convenience implementations which ignore the - * supplied status code and headers and return the relevant pre-defined {@code - * BodySubscriber}. + *

    An {@code HttpResponse} is not created directly, but rather returned as + * a result of sending an {@linkplain HttpRequest}. An {@code HttpResponse} is + * made available when the response status code and headers have been received, + * and typically after the response body has also been completely received. + * Whether or not the {@code HttpResponse} is made available before the response + * body has been completely received depends on the {@linkplain BodyHandler + * BodyHandler} provided when sending the {@code HttpRequest}. * - *

    See {@link BodyHandler} for example usage. + *

    This class provides methods for accessing the response status code, + * headers, the response body, and the {@code HttpRequest} corresponding + * to this response. + ** + * @param the response body type * - * @param the response body type * @since 11 */ public abstract class HttpResponse { @@ -178,76 +163,77 @@ /** * A handler for response bodies. * - *

    This is a function that takes two parameters: the response status code, - * and the response headers, and which returns a {@linkplain BodySubscriber}. - * The function is always called just before the response body is read. Its - * implementation may examine the status code or headers and must decide, - * whether to accept the response body or discard it, and if accepting it, - * exactly how to handle it. + *

    The {@code BodyHandler} interface allows inspection of the response + * code and headers, before the actual response body is received, and is + * responsible for creating the response {@linkplain BodySubscriber + * BodySubscriber}. The {@code BodySubscriber} consumes the actual response + * body bytes and converts them into a higher-level Java type. * - *

    Some pre-defined implementations which do not utilize the status code - * or headers (meaning the body is always accepted) are defined: + *

    A {@code BodyHandler} is a function that takes two parameters: the + * response status code and the response headers; and which returns a + * {@code BodySubscriber}. The {@code BodyHandler} is invoked when the + * response status code and headers are available, but before the response + * body bytes are received. + * + *

    A number of convenience static factory methods are provided that + * return pre-defined implementations that do not examine the status code + * (meaning the body is always accepted): *

    * - *

    These implementations return the equivalent {@link BodySubscriber}. - * Alternatively, the handler can be used to examine the status code - * or headers and return different body subscribers as appropriate. + *

    These implementations return an equivalently named {@code + * BodySubscriber}. Alternatively, a custom handler can be used to examine + * the status code or headers, and return different body subscribers as + * appropriate. * - *

    Examples of handler usage + *

    Examples: * - *

    The first example uses one of the predefined handler functions which - * ignores the response headers and status, and always process the response - * body in the same way. - *

    -     * {@code
    -     *      HttpResponse resp = HttpRequest
    -     *              .create(URI.create("http://www.foo.com"))
    -     *              .GET()
    -     *              .response(BodyHandler.asFile(Paths.get("/tmp/f")));
    -     * }
    -     * 
    - * Note, that even though these pre-defined handlers ignore the status code - * and headers, this information is still accessible from the - * {@code HttpResponse} when it is returned. + *

    The first example uses one of the predefined handler functions that + * always process the response body in the same way. + *

    {@code   HttpRequest request = HttpRequest.newBuilder()
    +     *        .uri(URI.create("http://www.foo.com/"))
    +     *        .build();
    +     *  client.sendAsync(request, BodyHandler.asFile(Paths.get("/tmp/f")))
    +     *        .thenApply(HttpResponse::body)
    +     *        .thenAccept(System.out::println) }
    + * Note, that even though these pre-defined handlers do not examine the + * response code, the response code and headers are always retrievable from + * the {@linkplain HttpResponse}, when it is returned. * *

    In the second example, the function returns a different subscriber * depending on the status code. - *

    -     * {@code
    -     *      HttpResponse resp1 = HttpRequest
    -     *              .create(URI.create("http://www.foo.com"))
    -     *              .GET()
    -     *              .response(
    -     *                  (status, headers) -> status == 200
    +     * 
    {@code   HttpRequest request = HttpRequest.newBuilder()
    +     *        .uri(URI.create("http://www.foo.com/"))
    +     *        .build();
    +     *  BodyHandler bodyHandler = (status, headers) -> status == 200
          *                      ? BodySubscriber.asFile(Paths.get("/tmp/f"))
          *                      : BodySubscriber.replace(Paths.get("/NULL")));
    -     * }
    -     * 
    + * client.sendAsync(request, bodyHandler)) + * .thenApply(HttpResponse::body) + * .thenAccept(System.out::println) }
    * * @param the response body type */ @FunctionalInterface public interface BodyHandler { /** - * Returns a {@link BodySubscriber BodySubscriber} considering the given - * response status code and headers. This method is always called before - * the body is read and its implementation can decide to keep the body - * and store it somewhere, or else discard it by returning the {@code - * BodySubscriber} returned from {@link BodySubscriber#discard() - * discard}. + * Returns a {@linkplain BodySubscriber BodySubscriber} considering the + * given response status code and headers. This method is invoked before + * the actual response body bytes are read and its implementation must + * return a {@code BodySubscriber} to consume the response body bytes. + * + *

    The response body can be discarded using one of {@linkplain + * #discard() discard} or {@linkplain #replace(Object) replace}. * * @param statusCode the HTTP status code received * @param responseHeaders the response headers received @@ -272,12 +258,10 @@ * BodySubscriber} and {@code Flow.Subscriber}. * *

    For example: - *

     {@code
    -         *  TextSubscriber subscriber = new TextSubscriber();
    +         * 
     {@code  TextSubscriber subscriber = new TextSubscriber();
              *  HttpResponse response = client.sendAsync(request,
              *      BodyHandler.fromSubscriber(subscriber)).join();
    -         *  System.out.println(response.statusCode());
    -         * }
    + * System.out.println(response.statusCode()); }
    * * @param subscriber the subscriber * @return a response body handler @@ -304,12 +288,10 @@ * 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();
    -         * }
    + *
     {@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 @@ -345,12 +327,10 @@ * BodySubscriber} and {@code Flow.Subscriber}. * *

    For example: - *

     {@code
    -         *  TextSubscriber subscriber = new TextSubscriber();
    +         * 
     {@code  TextSubscriber subscriber = new TextSubscriber();
              *  HttpResponse response = client.sendAsync(request,
              *      BodyHandler.fromLineSubscriber(subscriber, "\n")).join();
    -         *  System.out.println(response.statusCode());
    -         * }
    + * System.out.println(response.statusCode()); }
    * * @param subscriber the subscriber * @return a response body handler @@ -381,12 +361,10 @@ * 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, "\n")).join();
    -         * String text = response.body();
    -         * }
    + *
     {@code  TextSubscriber subscriber = ...;  // accumulates bytes and transforms them into a String
    +         *  HttpResponse response = client.sendAsync(request,
    +         *      BodyHandler.fromSubscriber(subscriber, TextSubscriber::getTextResult, "\n")).join();
    +         *  String text = response.body();  }
    * * @param the type of the Subscriber * @param the type of the response body @@ -749,7 +727,8 @@ } /** - * A subscriber for response bodies. + * A {@code BodySubscriber} consumes response body bytes and converts them + * into a higher-level Java type. * *

    The object acts as a {@link Flow.Subscriber}<{@link List}<{@link * ByteBuffer}>> to the HTTP client implementation, which publishes @@ -758,27 +737,27 @@ * is a strictly ordered representation of the response body. Both the Lists * and the ByteBuffers, once passed to the subscriber, are no longer used by * the HTTP client. The subscriber converts the incoming buffers of data to - * some user-defined object type {@code T}. - * - *

    The {@link #getBody()} method returns a {@link CompletionStage}{@code - * } that provides the response body object. The {@code CompletionStage} - * must be obtainable at any time. When it completes depends on the nature - * of type {@code T}. In many cases, when {@code T} represents the entire - * body after being read then it completes after the body has been read. If - * {@code T} is a streaming type such as {@link java.io.InputStream} then it - * completes before the body has been read, because the calling code uses it - * to consume the data. + * some higher-level Java type {@code T}. * - * @apiNote To ensure that all resources associated with the - * corresponding exchange are properly released, an implementation - * of {@code BodySubscriber} must ensure to {@linkplain - * Flow.Subscription#request request} more data until {@link - * #onComplete() onComplete} or {@link #onError(Throwable) onError} - * are signalled, or {@linkplain Flow.Subscription#request cancel} its - * {@linkplain #onSubscribe(Flow.Subscription) subscription} - * if unable or unwilling to do so. - * Calling {@code cancel} before exhausting the data may cause - * the underlying HTTP connection to be closed and prevent it + *

    The {@link #getBody()} method returns a + * {@link CompletionStage}<{@code T}> that provides the response body + * object. The {@code CompletionStage} must be obtainable at any time. When + * it completes depends on the nature of type {@code T}. In many cases, + * when {@code T} represents the entire body after being consumed then + * the {@code CompletionStage} completes after the body has been consumed. + * If {@code T} is a streaming type, such as {@link java.io.InputStream + * InputStream}, then it completes before the body has been read, because + * the calling code uses the {@code InputStream} to consume the data. + * + * @apiNote To ensure that all resources associated with the corresponding + * HTTP exchange are properly released, an implementation of {@code + * BodySubscriber} should ensure to {@linkplain Flow.Subscription#request + * request} more data until one of {@linkplain #onComplete() onComplete} or + * {@link #onError(Throwable) onError} are signalled, or {@linkplain + * Flow.Subscription#request cancel} its {@linkplain + * #onSubscribe(Flow.Subscription) subscription} if unable or unwilling to + * do so. Calling {@code cancel} before exhausting the response body data + * may cause the underlying HTTP connection to be closed and prevent it * from being reused for subsequent operations. * * @param the response body type @@ -790,7 +769,7 @@ * Returns a {@code CompletionStage} which when completed will return * the response body object. This method can be called at any time * relative to the other {@link Flow.Subscriber} methods and is invoked - * using the client's {@link Executor}. + * using the client's {@link HttpClient#executor() executor}. * * @return a CompletionStage for the response body */ @@ -1123,46 +1102,43 @@ } /** - * Returns a {@code BodySubscriber} whose response body is mapped - * using the supplied mapping function from one type {@code } to - * another type {@code }. The mapping function is executed - * using the {@link Executor} of the sending client and can - * therefore be used to map any response body type, including - * blocking {@link java.io.InputStream}s as shown in the following - * example which uses a well-known JSON parser to convert an {@code InputStream} - * into any annotated Java object type. - *

    - * Example usage - *

     {@code
    -         * public static  BodySubscriber asJSON(Class targetType) {
    +         * Returns a {@code BodySubscriber} whose response body value is that of
    +         * the result of applying the given function to the body object of the
    +         * given {@code upstream} {@code BodySubscriber}.
    +         *
    +         * 

    The mapping function is executed using the client's {@linkplain + * HttpClient#executor()}, and can therefore be used to map any response + * body type, including blocking {@linkplain InputStream}, as shown in + * the following example which uses a well-known JSON parser to convert + * an {@code InputStream} into any annotated Java object type. + * + *

    For example: + *

     {@code  public static  BodySubscriber asJSON(Class targetType) {
              *     BodySubscriber upstream = BodySubscriber.asInputStream();
              *
    -         *     BodySubscriber downstream = mappedFrom(
    +         *     BodySubscriber downstream = mapping(
              *           upstream,
              *           (InputStream is) -> {
              *               try (InputStream stream = is) {
              *                   ObjectMapper objectMapper = new ObjectMapper();
    -         *                   W result = objectMapper.readValue(stream, targetType);
    -         *                   return result;
    +         *                   return objectMapper.readValue(stream, targetType);
              *               } catch (IOException e) {
              *                   throw new UncheckedIOException(e);
              *               }
              *           });
              *    return downstream;
    -         * }
    -         * }
    + * } }
    * - * @param the type of the body subscriber to be mapped + * @param the upstream both type * @param the type of the body subscriber returned * @param upstream the body subscriber to be mapped * @param mapper the mapping function * @return a mapped body subscriber */ - public static BodySubscriber mappedFrom( - BodySubscriber upstream, - Function mapper) + public static BodySubscriber mapping(BodySubscriber upstream, + Function mapper) { - return new ResponseSubscribers.MappedSubscriber(upstream, mapper); + return new ResponseSubscribers.MappingSubscriber(upstream, mapper); } } } diff -r 881f0ecb513f -r 15dc43936d39 src/java.net.http/share/classes/java/net/http/package-info.java --- a/src/java.net.http/share/classes/java/net/http/package-info.java Wed Feb 07 22:49:25 2018 +0000 +++ b/src/java.net.http/share/classes/java/net/http/package-info.java Thu Feb 08 20:58:35 2018 +0000 @@ -36,20 +36,20 @@ *
  • {@link java.net.http.WebSocket}
  • * * - *

    The API functions asynchronously (using {@link java.util.concurrent.CompletableFuture}) - * and work is done on the threads supplied by the client's {@link java.util.concurrent.Executor} - * where practical. - * - *

    {@code HttpClient} also provides a simple synchronous mode, where all - * work may be done on the calling thread. + *

    Asynchronous tasks and dependent actions of returned {@link + * java.util.concurrent.CompletableFuture} instances are executed on the threads + * supplied by the client's {@link java.util.concurrent.Executor}, where + * practical. * - *

    {@code CompletableFuture}s returned by this API will throw {@link java.lang.UnsupportedOperationException} - * for their {@link java.util.concurrent.CompletableFuture#obtrudeValue(Object) obtrudeValue} - * and {@link java.util.concurrent.CompletableFuture#obtrudeException(Throwable) obtrudeException} - * methods. Invoking the {@link java.util.concurrent.CompletableFuture#cancel cancel} - * method on a {@code CompletableFuture} returned by this API will not interrupt - * the underlying operation, but may be useful to complete, exceptionally, - * dependent stages that have not already completed. + *

    {@code CompletableFuture}s returned by this API will throw {@link + * java.lang.UnsupportedOperationException} for their {@link + * java.util.concurrent.CompletableFuture#obtrudeValue(Object) obtrudeValue} + * and {@link java.util.concurrent.CompletableFuture#obtrudeException(Throwable) + * obtrudeException} methods. Invoking the {@link + * java.util.concurrent.CompletableFuture#cancel cancel} method on a {@code + * CompletableFuture} returned by this API will not interrupt the underlying + * operation, but may be useful to complete, exceptionally, dependent stages + * that have not already completed. * *

    Unless otherwise stated, {@code null} parameter values will cause methods * of all classes in this package to throw {@code NullPointerException}. diff -r 881f0ecb513f -r 15dc43936d39 src/java.net.http/share/classes/jdk/internal/net/http/ResponseSubscribers.java --- a/src/java.net.http/share/classes/jdk/internal/net/http/ResponseSubscribers.java Wed Feb 07 22:49:25 2018 +0000 +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ResponseSubscribers.java Thu Feb 08 20:58:35 2018 +0000 @@ -48,8 +48,6 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executor; import java.util.concurrent.Flow; import java.util.concurrent.Flow.Subscriber; import java.util.concurrent.Flow.Subscription; @@ -475,7 +473,7 @@ public static BodySubscriber> createLineStream(Charset charset) { Objects.requireNonNull(charset); BodySubscriber s = new HttpResponseInputStream(); - return new MappedSubscriber>(s, + return new MappingSubscriber>(s, (InputStream stream) -> { return new BufferedReader(new InputStreamReader(stream, charset)) .lines().onClose(() -> Utils.close(stream)); @@ -602,29 +600,21 @@ * of the upstream {@code getBody()} and applies the mapper function to * obtain the new {@code CompletionStage} type. * - * Uses an Executor that must be set externally. - * * @param the upstream body type * @param this subscriber's body type */ - public static class MappedSubscriber implements BodySubscriber { - final BodySubscriber upstream; - final Function mapper; + public static class MappingSubscriber implements BodySubscriber { + private final BodySubscriber upstream; + private final Function mapper; - /** - * - * @param upstream - * @param mapper - */ - public MappedSubscriber(BodySubscriber upstream, Function mapper) { - this.upstream = upstream; - this.mapper = mapper; + public MappingSubscriber(BodySubscriber upstream, Function mapper) { + this.upstream = Objects.requireNonNull(upstream); + this.mapper = Objects.requireNonNull(mapper); } @Override public CompletionStage getBody() { - return upstream.getBody() - .thenApply(mapper); + return upstream.getBody().thenApply(mapper); } @Override diff -r 881f0ecb513f -r 15dc43936d39 test/jdk/java/net/httpclient/MappedResponseSubscriber.java --- a/test/jdk/java/net/httpclient/MappedResponseSubscriber.java Wed Feb 07 22:49:25 2018 +0000 +++ b/test/jdk/java/net/httpclient/MappedResponseSubscriber.java Thu Feb 08 20:58:35 2018 +0000 @@ -137,7 +137,7 @@ @Override public BodySubscriber apply(int statusCode, HttpHeaders responseHeaders) { assertEquals(statusCode, 200); - return HttpResponse.BodySubscriber.mappedFrom( + return HttpResponse.BodySubscriber.mapping( new CRSBodySubscriber(), (s) -> s.getBytes() ); } diff -r 881f0ecb513f -r 15dc43936d39 test/jdk/java/net/httpclient/SubscriberPublisherAPIExceptions.java --- a/test/jdk/java/net/httpclient/SubscriberPublisherAPIExceptions.java Wed Feb 07 22:49:25 2018 +0000 +++ b/test/jdk/java/net/httpclient/SubscriberPublisherAPIExceptions.java Thu Feb 08 20:58:35 2018 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.net.http.HttpRequest.BodyPublisher; import java.net.http.HttpResponse.BodyHandler; import java.net.http.HttpResponse.BodySubscriber; +import java.util.function.Function; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static java.nio.charset.StandardCharsets.UTF_8; @@ -130,6 +131,9 @@ assertThrows(IAE, () -> BodySubscriber.buffering(new NoOpSubscriber(), 0)); assertThrows(IAE, () -> BodySubscriber.buffering(new NoOpSubscriber(), -1)); assertThrows(IAE, () -> BodySubscriber.buffering(new NoOpSubscriber(), Integer.MIN_VALUE)); + assertThrows(NPE, () -> BodySubscriber.mapping(null, Function.identity())); + assertThrows(NPE, () -> BodySubscriber.mapping(BodySubscriber.asByteArray(), null)); + assertThrows(NPE, () -> BodySubscriber.mapping(null, null)); } static class NoOpHandler implements BodyHandler {