Jetty HTTP Client Transport
Maven Dependencies
<!-- Juneau transport adapter -->
<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-rest-client-jetty</artifactId>
<version>${juneau.version}</version>
</dependency>
<!-- Jetty 12 HTTP Client (transitive from the adapter, pinned here for clarity) -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<version>12.1.9</version>
</dependency>
Overview
juneau-rest-client-jetty provides an HttpTransport implementation backed by the Jetty 12
HttpClient (org.eclipse.jetty:jetty-client). Consider it when:
- Your application already embeds a Jetty server (e.g., via juneau-microservice-jetty) and you want to share the same Jetty lifecycle for outbound HTTP calls.
- You want a Jetty-native HTTP client without pulling in Apache HttpComponents or OkHttp.
The request body is streamed via OutputStreamRequestContent on a background thread, so large
bodies do not require full in-memory buffering. Response body bytes are made available as an
InputStream via Jetty's InputStreamResponseListener.
The transport is auto-discovered via ServiceLoader when the module is on the classpath. An
explicit .transport(...) call always wins over auto-discovery.
Getting Started
Zero-configuration default
JettyHttpTransport.create() and JettyHttpTransportBuilder.build() declare throws Exception
because they may need to start the underlying Jetty HttpClient.
import org.apache.juneau.marshall.json5.*;
import org.apache.juneau.rest.client.*;
import org.apache.juneau.rest.client.jetty.*;
RestClient client;
try {
client = RestClient.builder()
.transport(JettyHttpTransport.create()) // starts a new HttpClient internally
.serializer(Json5Serializer.DEFAULT)
.parser(Json5Parser.DEFAULT)
.rootUrl("https://api.example.com")
.build();
} catch (Exception e) {
throw new RuntimeException("Failed to start Jetty transport", e);
}
try (var resp = client.get("/users/123").run()) {
var user = resp.body().as(User.class);
}
client.close();
JettyHttpTransport.create() is shorthand for JettyHttpTransport.builder().build(). It
creates and starts a new HttpClient with default settings and a 30-second response-header
timeout.
Auto-discovery
Add the module to the classpath and omit the .transport(...) call:
RestClient client = RestClient.builder()
.serializer(Json5Serializer.DEFAULT)
.parser(Json5Parser.DEFAULT)
.rootUrl("https://api.example.com")
.build();
Auto-discovery uses the same throws Exception build path internally; the exception is wrapped
in an IllegalStateException if thrown.
Configuring the Underlying HttpClient
Use JettyHttpTransportBuilder to supply a pre-configured HttpClient or to adjust the
response-header timeout.
import org.eclipse.jetty.client.*;
import org.apache.juneau.rest.client.*;
import org.apache.juneau.rest.client.jetty.*;
// Build your own Jetty HttpClient
HttpClient jettyClient = new HttpClient();
// ... configure jettyClient ...
RestClient client;
try {
client = RestClient.builder()
.transport(JettyHttpTransport.builder()
.httpClient(jettyClient)
.responseTimeoutMs(15_000) // wait up to 15 s for response headers
.build())
.serializer(Json5Serializer.DEFAULT)
.parser(Json5Parser.DEFAULT)
.rootUrl("https://api.example.com")
.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
If the HttpClient you supply has not been started, JettyHttpTransport starts it automatically.
Response-Header Timeout
JettyHttpTransportBuilder.responseTimeoutMs(long) sets the maximum time to wait (in
milliseconds) for the HTTP status line and headers after the request has been sent. It does not
limit how long the response body takes to stream.
| Value | Behaviour |
|---|---|
> 0 (default: 30_000) | Wait that many milliseconds; throw TransportException on timeout. |
0 or negative | Wait indefinitely. |
JettyHttpTransport transport = JettyHttpTransport.builder()
.responseTimeoutMs(60_000) // 60 s for slow endpoints
.build();
SSL / TLS
Configure SSL on the HttpClient before passing it to the builder:
import org.eclipse.jetty.client.*;
import org.eclipse.jetty.util.ssl.*;
SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
sslContextFactory.setKeyStorePath("/path/to/keystore.jks");
sslContextFactory.setKeyStorePassword("secret");
HttpClient tlsClient = new HttpClient(sslContextFactory);
JettyHttpTransport transport = JettyHttpTransport.builder()
.httpClient(tlsClient)
.build();
Lifecycle Management
JettyHttpTransport.close() calls HttpClient.stop(). Map this to RestClient.close():
RestClient client = RestClient.builder()
.transport(JettyHttpTransport.builder().build())
.build();
// ... application runs ...
// At shutdown — stops the Jetty HttpClient
client.close();
When embedding inside a JettyMicroservice, the transport's lifecycle aligns naturally with the
server because both use the same Jetty runtime. If you pass your own HttpClient to the adapter,
stopping the client via RestClient.close() also stops that shared instance — factor this in
if other components depend on it.
See Also
- HTTP Transport Adapters — overview and adapter comparison
- Next-Generation REST Client — full guide to the NG client
- juneau-microservice-jetty — embedding Juneau with Jetty