diff --git a/docs/src/main/docbook/client.xml b/docs/src/main/docbook/client.xml
index 90964a3b0a..e0b01cb86b 100644
--- a/docs/src/main/docbook/client.xml
+++ b/docs/src/main/docbook/client.xml
@@ -999,4 +999,135 @@ Client client = ClientBuilder.newBuilder().sslContext(sslContext).build();
+
+
+ InvocationInterceptors
+
+ Suppose a case that the start of the request is to be logged and even measured.
+ This can be done by ClientRequestFilter, which is usually invoked before the request is wired on the network.
+ However, the filter may be called as a last of the filters in the chain. Sure, it can have the highest priority,
+ but the other filters can have the very same priority! Some long-running operations can be performed before the
+ measuring can actually start. Even worse, the filter may even be skipped from the chain by the previous
+ #abortWith!
+
+
+ PreInvocationInterceptor
+
+ For this, PreInvocationInterceptor, the code that executes before the ClientRequestFilters
+ are invoked, has been added to the client request chain. Jersey ensures all the interceptors are invoked with each request.
+ The interceptor contains a single #beforeRequest method, which corresponds to ClientRequestFilter:
+
+
+ /**
+ * The method invoked before the request starts.
+ * @param requestContext the request context shared with
+ * ClientRequestFilter.
+ */
+ void beforeRequest(ClientRequestContext requestContext);
+
+
+ Note that only a single #abortWith is allowed in all PreInvocationInterceptors,
+ otherwise an IllegalStateException is thrown.
+ All the exceptions accumulated in PreInvocationInterceptors are thrown in a single Exception,
+ available through #getSuppressed().
+
+
+
+ PostInvocationInterceptor
+
+ Similarly, ClientResponseFilter seems to be a good place where the total time of the HTTP request can be measured,
+ but similarly to ClientRequestFilter, the response filter may not be invoked at all.
+ For this, PostInvocationInterceptor has been introduced. Jersey runtime ensures that every
+ PostInvocationInterceptor is called. Since an exception can occur during the HTTP request,
+ PostInvocationInterceptor comes with two methods:
+
+
+ /**
+ * The method is invoked after a request when no
+ * is thrown, or the Throwables are resolved
+ * by previous PostInvocationInterceptor.
+ *
+ * @param requestContext the request context.
+ * @param responseContext the response context
+ * of the original Response or response context
+ * defined by the new resolving Response.
+ */
+ void afterRequest(ClientRequestContext requestContext, ClientResponseContext responseContext);
+
+ /**
+ * The method is invoked after a Throwable is caught
+ * during the client request chain processing.
+ *
+ * @param requestContext the request context.
+ * @param exceptionContext the context available to handle the
+ * caught Throwables.
+ */
+ void onException(ClientRequestContext requestContext, ExceptionContext exceptionContext);
+
+
+ The #afterRequest method is executed when no exception has been thrown during the HTTP request,
+ #onException method is executed if the exception has been thrown during the request.
+ It is possible to set a response in #onException, and the consecutive PostInvocationInterceptor will
+ execute its #afterRequest method.
+
+ The measuring example can looks as follows, then:
+
+
+ String response = ClientBuilder.newClient().target("path")
+ .register(new PreInvocationInterceptor() {
+ @Override
+ public void beforeRequest(ClientRequestContext requestContext) {
+ startTime = System.currentTimeMillis();
+ }
+ })
+ .register(new PostInvocationInterceptor() {
+ @Override
+ public void afterRequest(ClientRequestContext requestContext, ClientResponseContext responseContext) {
+ logDuration(System.currentTimeMillis() - startTime);
+ }
+ @Override
+ public void onException(ClientRequestContext requestContext, ExceptionContext exceptionContext) {
+ logDuration(System.currentTimeMillis() - startTime);
+ }
+ })
+ .request().get().readEntity(String.class);
+
+
+
+
+ InvocationBuilderListener
+
+ InvocationBuilderListener is an interface that is inspired by Microprofile REST Client RestClientBuilderListener
+ and it contains a single method:
+
+
+ /**
+ * Whenever an Invocation.Builder is created, (i.e. when
+ * WebTarget#request() is called, this method would be invoked.
+ *
+ * @param context the updated InvocationBuilderContext.
+ */
+ void onNewBuilder(InvocationBuilderContext context);
+
+
+ InvocationBuilderContext a subset of methods of the Invocation.Builder. It can be used to call the default
+ values of the Invocation.Builder. Since it is invoked at the time Invocation.Builder is instantiated, any consequent
+ calls of the Invocation.Builder‘s methods will replace the defaults set by the InvocationBuilderListener.
+
+ For instance, if all the HTTP requests should contain a custom HTTP header,
+ there can be created a feature that would be registered on the client:
+
+
+ public static class MyFeature implements Feature {
+ @Override
+ public boolean configure(FeatureContext context) {
+ context.register(
+ (InvocationBuilderListener)(l)->
+ l.getHeaders().add("MY_HEADER", "MY_VALUE")
+ );
+ return true;
+ }
+ }
+
+