--- 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 \
--- 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.
*
- * <p> 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.
+ * <p> 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.
*
* <p> An {@code HttpClient} provides configuration information, and resource
* sharing, for all requests send through it.
*
- * <p>For Example:
+ * <p> Requests can be made either synchronously or asynchronously:
+ * <ul>
+ * <li>{@link HttpClient#send(HttpRequest, BodyHandler)} blocks
+ * until the request has been sent and the response has been received.</li>
+ *
+ * <li>{@link HttpClient#sendAsync(HttpRequest, BodyHandler)} sends the
+ * request and receives the response asynchronously. The {@code sendAsync}
+ * method returns immediately with a {@linkplain CompletableFuture
+ * CompletableFuture}<{@linkplain HttpResponse}>. The {@code
+ * CompletableFuture} completes when the response becomes available. The
+ * returned {@code CompletableFuture} can be combined in different ways to
+ * declare dependencies among several asynchronous tasks.</li>
+ * </ul>
+ *
+ * <p> 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 <T>} of
+ * the response body.
+ *
+ * <p><b>Synchronous Example</b>
* <pre>{@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<String> response = client.send(request, BodyHandler.asString());
+ * System.out.println(response.statusCode());
+ * System.out.println(response.body()); }</pre>
*
- * HttpRequest request = HttpRequest.newBuilder()
- * .uri(URI.create("http://foo.com/"))
+ * <p><b>Asynchronous Example</b>
+ * <pre>{@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(); }</pre>
*
- * <p> See {@link HttpRequest} for further examples of usage of this API.
+ * <p> <a id="securitychecks"></a><b>Security checks</b></a>
+ *
+ * <p> 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.
*
* <p> 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.
*
* <p> 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 <T> 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
- * <a href="HttpRequest.html#securitychecks">security checks</a>.
+ * See <a href="#securitychecks">security checks</a> for further
+ * information.
*/
public abstract <T> HttpResponse<T>
- send(HttpRequest req, HttpResponse.BodyHandler<T> responseBodyHandler)
+ send(HttpRequest request, HttpResponse.BodyHandler<T> 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.
*
- * <p> Equivalent to {@code sendAsync(request, responseBodyHandler, null)}.
+ * <p> Equivalent to: {@code sendAsync(request, responseBodyHandler, null)}.
*
* @param <T> the response body type
* @param request the request
@@ -492,8 +539,8 @@
* <li>{@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
- * <a href="HttpRequest.html#securitychecks">security checks</a>.</li>
+ * See <a href="#securitychecks">security checks</a> for further
+ * information.</li>
* </ul>
*
* @param <T> the response body type
@@ -511,24 +558,20 @@
* Creates a new {@code WebSocket} builder (optional operation).
*
* <p> <b>Example</b>
- * <pre>{@code
- * HttpClient client = HttpClient.newHttpClient();
+ * <pre>{@code HttpClient client = HttpClient.newHttpClient();
* CompletableFuture<WebSocket> ws = client.newWebSocketBuilder()
- * .buildAsync(URI.create("ws://websocket.example.com"), listener);
- * }</pre>
+ * .buildAsync(URI.create("ws://websocket.example.com"), listener); }</pre>
*
* <p> Finer control over the WebSocket Opening Handshake can be achieved
* by using a custom {@code HttpClient}.
*
* <p> <b>Example</b>
- * <pre>{@code
- * InetSocketAddress addr = new InetSocketAddress("proxy.example.com", 80);
+ * <pre>{@code InetSocketAddress addr = new InetSocketAddress("proxy.example.com", 80);
* HttpClient client = HttpClient.newBuilder()
* .proxy(ProxySelector.of(addr))
* .build();
* CompletableFuture<WebSocket> ws = client.newWebSocketBuilder()
- * .buildAsync(URI.create("ws://websocket.example.com"), listener);
- * }</pre>
+ * .buildAsync(URI.create("ws://websocket.example.com"), listener); }</pre>
*
* <p> A {@code WebSocket.Builder} returned from this method is not safe for
* use by multiple threads without external synchronization.
--- 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.
*
- * <p> An {@code HttpRequest} instance is built through a {@code HttpRequest}
+ * <p> 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.
*
- * <p> <b>Example HTTP interactions:</b>
- * <pre>{@code // GET
- * HttpResponse<String> 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();
+ * <p><b>Example:</b> GET request that prints the response body as a String
+ * <pre>{@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(); }</pre>
*
- * // POST
- * HttpResponse<Path> 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" }</pre>
- *
- * <p> The request is sent and the response obtained by invoking one of the
- * following methods in {@link HttpClient}.
- * <ul><li>{@link HttpClient#send(HttpRequest, BodyHandler)} blocks
- * until the entire request has been sent and the response has been received.</li>
- * <li>{@link HttpClient#sendAsync(HttpRequest, BodyHandler)} sends the
- * request and receives the response asynchronously. Returns immediately with a
- * {@linkplain CompletableFuture CompletableFuture}<{@linkplain HttpResponse}>.</li>
- * </ul>
- *
- * <p> 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 <T>} of the response body. See below.
- *
- * <p> <b>Request bodies</b>
+ * <p><b>Request bodies</b>
*
* <p> 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}.
* <ul>
* <li>{@link BodyPublisher#fromByteArray(byte[]) fromByteArray(byte[])} from byte array</li>
* <li>{@link BodyPublisher#fromByteArrays(Iterable) fromByteArrays(Iterable)}
@@ -118,114 +91,7 @@
* <li>{@link BodyPublisher#noBody() noBody()} no request body is sent</li>
* </ul>
*
- * <p> <b>Response bodies</b>
- *
- * <p> 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 <T>} 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}:
- *
- * <p> <b>Some of the pre-defined body handlers</b><br>
- * <ul>
- * <li>{@link BodyHandler#asByteArray() BodyHandler.asByteArray()}
- * stores the body in a byte array</li>
- * <li>{@link BodyHandler#asString() BodyHandler.asString()}
- * stores the body as a String </li>
- * <li>{@link BodyHandler#asFile(java.nio.file.Path)
- * BodyHandler.asFile(Path)} stores the body in a named file</li>
- * <li>{@link BodyHandler#replace(Object) BodyHandler.replace(Objectt)}
- * discards the response body and returns the given replacement value instead.</li>
- * </ul>
- *
- * <p> <b>Blocking/asynchronous behavior and thread usage</b>
- *
- * <p> There are two styles of request sending: <i>synchronous</i> and
- * <i>asynchronous</i>. {@link HttpClient#send(HttpRequest, HttpResponse.BodyHandler) }
- * blocks the calling thread until the request has been sent and the response received.
- *
- * <p> {@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.
- *
- * <p> 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.
- *
- * <p> <a id="securitychecks"></a><b>Security checks</b></a>
- *
- * <p> 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.
- *
- * <p> 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}.
- *
- * <p> <b>Examples</b>
- * <pre>{@code HttpClient client = HttpClient.newHttpClient();
- *
- * HttpRequest request = HttpRequest
- * .newBuilder(URI.create("http://www.foo.com/"))
- * .POST(BodyPublisher.fromString("Hello world"))
- * .build();
- *
- * HttpResponse<Path> response =
- * client.send(request, BodyHandler.asFile(Paths.get("/path")));
- *
- * Path body = response.body(); }</pre>
- *
- * <p><b>Asynchronous Example</b>
- *
- * <p> 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 <HttpResponse>}
- * 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}.
- * <pre>{@code // fetch a list of target URIs asynchronously and store them in Files.
- *
- * List<URI> targets = ...
- *
- * List<CompletableFuture<File>> 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 }</pre>
+ * <p> 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}.
*
* <p> Instances of {@code HttpRequest.Builder} are created by calling {@link
* HttpRequest#newBuilder(URI)} or {@link HttpRequest#newBuilder()}.
@@ -245,16 +111,15 @@
* <p> Each of the setter methods in this class modifies the state of the
* builder and returns <i>this</i> (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.
*
* <p> 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.
*
- * <p> 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<Duration> 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.
*
- * <p> The {@code BodyPublisher} class implements {@link Flow.Publisher
- * Flow.Publisher<ByteBuffer>} which means that a {@code BodyPublisher}
+ * <p> 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}.
*
- * <p> 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.
+ * <p> 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.
*
- * <p> 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.
+ * <p> 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<ByteBuffer> {
--- 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}.
- *
- * <p> 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.
- *
- * <p> Methods are provided in this class for accessing the response headers,
- * and response body.
- *
- * <p><b>Response handlers and subscribers</b>
+ * An HTTP response.
*
- * <p> 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}.
+ * <p> 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}.
*
- * <p> See {@link BodyHandler} for example usage.
+ * <p> This class provides methods for accessing the response status code,
+ * headers, the response body, and the {@code HttpRequest} corresponding
+ * to this response.
+ **
+ * @param <T> the response body type
*
- * @param <T> the response body type
* @since 11
*/
public abstract class HttpResponse<T> {
@@ -178,76 +163,77 @@
/**
* A handler for response bodies.
*
- * <p> 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.
+ * <p> 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.
*
- * <p> Some pre-defined implementations which do not utilize the status code
- * or headers (meaning the body is always accepted) are defined:
+ * <p> 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.
+ *
+ * <p> 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):
* <ul><li>{@link #asByteArray() }</li>
* <li>{@link #asByteArrayConsumer(java.util.function.Consumer)
* asByteArrayConsumer(Consumer)}</li>
* <li>{@link #asString(java.nio.charset.Charset) asString(Charset)}</li>
- * <li>{@link #asFile(Path, OpenOption...)
- * asFile(Path,OpenOption...)}</li>
+ * <li>{@link #asFile(Path, OpenOption...) asFile(Path,OpenOption...)}</li>
* <li>{@link #asFileDownload(java.nio.file.Path,OpenOption...)
* asFileDownload(Path,OpenOption...)}</li>
* <li>{@link #asInputStream() asInputStream()}</li>
* <li>{@link #discard() }</li>
* <li>{@link #replace(Object) }</li>
- * <li>{@link #buffering(BodyHandler, int)
- * buffering(BodyHandler,int)}</li>
+ * <li>{@link #buffering(BodyHandler, int) buffering(BodyHandler,int)}</li>
* </ul>
*
- * <p> 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.
+ * <p> 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.
*
- * <p><b>Examples of handler usage</b>
+ * <p><b>Examples:</b>
*
- * <p> 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.
- * <pre>
- * {@code
- * HttpResponse<Path> resp = HttpRequest
- * .create(URI.create("http://www.foo.com"))
- * .GET()
- * .response(BodyHandler.asFile(Paths.get("/tmp/f")));
- * }
- * </pre>
- * 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.
+ * <p> The first example uses one of the predefined handler functions that
+ * always process the response body in the same way.
+ * <pre>{@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) }</pre>
+ * 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.
*
* <p> In the second example, the function returns a different subscriber
* depending on the status code.
- * <pre>
- * {@code
- * HttpResponse<Path> resp1 = HttpRequest
- * .create(URI.create("http://www.foo.com"))
- * .GET()
- * .response(
- * (status, headers) -> status == 200
+ * <pre>{@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")));
- * }
- * </pre>
+ * client.sendAsync(request, bodyHandler))
+ * .thenApply(HttpResponse::body)
+ * .thenAccept(System.out::println) }</pre>
*
* @param <T> the response body type
*/
@FunctionalInterface
public interface BodyHandler<T> {
/**
- * 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.
+ *
+ * <p> 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}.
*
* <p> For example:
- * <pre> {@code
- * TextSubscriber subscriber = new TextSubscriber();
+ * <pre> {@code TextSubscriber subscriber = new TextSubscriber();
* HttpResponse<Void> response = client.sendAsync(request,
* BodyHandler.fromSubscriber(subscriber)).join();
- * System.out.println(response.statusCode());
- * }</pre>
+ * System.out.println(response.statusCode()); }</pre>
*
* @param subscriber the subscriber
* @return a response body handler
@@ -304,12 +288,10 @@
* BodySubscriber} and {@code Flow.Subscriber}.
*
* <p> For example:
- * <pre> {@code
- * TextSubscriber subscriber = ...; // accumulates bytes and transforms them into a String
- * HttpResponse<String> response = client.sendAsync(request,
- * BodyHandler.fromSubscriber(subscriber, TextSubscriber::getTextResult)).join();
- * String text = response.body();
- * }</pre>
+ * <pre> {@code TextSubscriber subscriber = ...; // accumulates bytes and transforms them into a String
+ * HttpResponse<String> response = client.sendAsync(request,
+ * BodyHandler.fromSubscriber(subscriber, TextSubscriber::getTextResult)).join();
+ * String text = response.body(); }</pre>
*
* @param <S> the type of the Subscriber
* @param <T> the type of the response body
@@ -345,12 +327,10 @@
* BodySubscriber} and {@code Flow.Subscriber}.
*
* <p> For example:
- * <pre> {@code
- * TextSubscriber subscriber = new TextSubscriber();
+ * <pre> {@code TextSubscriber subscriber = new TextSubscriber();
* HttpResponse<Void> response = client.sendAsync(request,
* BodyHandler.fromLineSubscriber(subscriber, "\n")).join();
- * System.out.println(response.statusCode());
- * }</pre>
+ * System.out.println(response.statusCode()); }</pre>
*
* @param subscriber the subscriber
* @return a response body handler
@@ -381,12 +361,10 @@
* BodySubscriber} and {@code Flow.Subscriber}.
*
* <p> For example:
- * <pre> {@code
- * TextSubscriber subscriber = ...; // accumulates bytes and transforms them into a String
- * HttpResponse<String> response = client.sendAsync(request,
- * BodyHandler.fromSubscriber(subscriber, TextSubscriber::getTextResult, "\n")).join();
- * String text = response.body();
- * }</pre>
+ * <pre> {@code TextSubscriber subscriber = ...; // accumulates bytes and transforms them into a String
+ * HttpResponse<String> response = client.sendAsync(request,
+ * BodyHandler.fromSubscriber(subscriber, TextSubscriber::getTextResult, "\n")).join();
+ * String text = response.body(); }</pre>
*
* @param <S> the type of the Subscriber
* @param <T> 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.
*
* <p> 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}.
- *
- * <p> 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 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
+ * <p> 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 <T> 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 <T>} to
- * another type {@code <U>}. 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.
- * <p>
- * <b>Example usage</b>
- * <p> <pre> {@code
- * public static <W> BodySubscriber<W> asJSON(Class<W> 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}.
+ *
+ * <p> 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.
+ *
+ * <p>For example:
+ * <pre> {@code public static <W> BodySubscriber<W> asJSON(Class<W> targetType) {
* BodySubscriber<InputStream> upstream = BodySubscriber.asInputStream();
*
- * BodySubscriber<W> downstream = mappedFrom(
+ * BodySubscriber<W> 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;
- * }
- * }</pre>
+ * } }</pre>
*
- * @param <T> the type of the body subscriber to be mapped
+ * @param <T> the upstream both type
* @param <U> 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 <T,U> BodySubscriber<U> mappedFrom(
- BodySubscriber<T> upstream,
- Function<T, U> mapper)
+ public static <T,U> BodySubscriber<U> mapping(BodySubscriber<T> upstream,
+ Function<T, U> mapper)
{
- return new ResponseSubscribers.MappedSubscriber<T, U>(upstream, mapper);
+ return new ResponseSubscribers.MappingSubscriber<T, U>(upstream, mapper);
}
}
}
--- 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 @@
* <li>{@link java.net.http.WebSocket}</li>
* </ul>
*
- * <p> 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.
- *
- * <p> {@code HttpClient} also provides a simple synchronous mode, where all
- * work may be done on the calling thread.
+ * <p> 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.
*
- * <p> {@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.
+ * <p> {@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.
*
* <p> Unless otherwise stated, {@code null} parameter values will cause methods
* of all classes in this package to throw {@code NullPointerException}.
--- 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<Stream<String>> createLineStream(Charset charset) {
Objects.requireNonNull(charset);
BodySubscriber<InputStream> s = new HttpResponseInputStream();
- return new MappedSubscriber<InputStream,Stream<String>>(s,
+ return new MappingSubscriber<InputStream,Stream<String>>(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 <T> the upstream body type
* @param <U> this subscriber's body type
*/
- public static class MappedSubscriber<T,U> implements BodySubscriber<U> {
- final BodySubscriber<T> upstream;
- final Function<T,U> mapper;
+ public static class MappingSubscriber<T,U> implements BodySubscriber<U> {
+ private final BodySubscriber<T> upstream;
+ private final Function<T,U> mapper;
- /**
- *
- * @param upstream
- * @param mapper
- */
- public MappedSubscriber(BodySubscriber<T> upstream, Function<T,U> mapper) {
- this.upstream = upstream;
- this.mapper = mapper;
+ public MappingSubscriber(BodySubscriber<T> upstream, Function<T,U> mapper) {
+ this.upstream = Objects.requireNonNull(upstream);
+ this.mapper = Objects.requireNonNull(mapper);
}
@Override
public CompletionStage<U> getBody() {
- return upstream.getBody()
- .thenApply(mapper);
+ return upstream.getBody().thenApply(mapper);
}
@Override
--- 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<byte[]> apply(int statusCode, HttpHeaders responseHeaders) {
assertEquals(statusCode, 200);
- return HttpResponse.BodySubscriber.mappedFrom(
+ return HttpResponse.BodySubscriber.mapping(
new CRSBodySubscriber(), (s) -> s.getBytes()
);
}
--- 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<Void> {