Jersey core client implementation for building RESTful web service clients using JAX-RS API
—
Service Provider Interface for pluggable HTTP transport connectors and extensibility hooks including custom connectors, request/response interceptors, client lifecycle listeners, and async callback mechanisms. This functionality enables deep customization and integration with different HTTP client implementations.
Core interface for providing HTTP transport connectors that handle the actual HTTP communication.
/**
* Contract for providing client transport connectors
*/
public interface ConnectorProvider {
/**
* Create connector instance for the given client and configuration
* @param client client instance requesting the connector
* @param runtimeConfig runtime configuration for the connector
* @return configured connector instance
*/
Connector getConnector(Client client, Configuration runtimeConfig);
}Core connector interface that handles HTTP request execution with support for both synchronous and asynchronous operations.
/**
* Client transport connector for executing HTTP requests
*/
public interface Connector extends Inflector<ClientRequest, ClientResponse> {
/**
* Execute HTTP request synchronously
* @param request client request to execute
* @return client response
*/
ClientResponse apply(ClientRequest request);
/**
* Execute HTTP request asynchronously
* @param request client request to execute
* @param callback callback for handling response or failure
* @return Future representing the async operation
*/
Future<?> apply(ClientRequest request, AsyncConnectorCallback callback);
/**
* Get connector name for identification
* @return connector name
*/
String getName();
/**
* Close connector and release resources
*/
void close();
}Callback interface for handling asynchronous HTTP request results and failures.
/**
* Callback interface for asynchronous connector operations
*/
public interface AsyncConnectorCallback {
/**
* Handle successful response
* @param response client response from successful request
*/
void response(ClientResponse response);
/**
* Handle request failure
* @param failure throwable representing the failure cause
*/
void failure(Throwable failure);
}Default connector provider implementation using Java's built-in HttpURLConnection for HTTP transport.
public class HttpUrlConnectorProvider implements ConnectorProvider {
// Configuration properties
public static final String USE_FIXED_LENGTH_STREAMING = "jersey.config.client.httpUrlConnector.useFixedLengthStreaming";
public static final String SET_METHOD_WORKAROUND = "jersey.config.client.httpUrlConnector.setMethodWorkaround";
/**
* Create default HTTP URL connector provider
*/
public HttpUrlConnectorProvider();
/**
* Configure connector with custom connection factory
* @param connectionFactory factory for creating HTTP connections
* @return configured connector provider
*/
public HttpUrlConnectorProvider connectionFactory(ConnectionFactory connectionFactory);
/**
* Configure chunk size for chunked encoding
* @param chunkSize chunk size in bytes
* @return configured connector provider
*/
public HttpUrlConnectorProvider chunkSize(int chunkSize);
/**
* Enable fixed-length streaming mode
* @return configured connector provider
*/
public HttpUrlConnectorProvider useFixedLengthStreaming();
/**
* Enable HTTP method workaround for restricted methods
* @return configured connector provider
*/
public HttpUrlConnectorProvider useSetMethodWorkaround();
/**
* Create connector instance
* @param client client instance
* @param config runtime configuration
* @return HTTP URL connector instance
*/
public Connector getConnector(Client client, Configuration config);
}Factory interface for creating HTTP URL connections with optional proxy support.
/**
* Factory for creating HTTP URL connections
*/
public interface ConnectionFactory {
/**
* Create HTTP connection for the given URL
* @param url target URL for connection
* @return HTTP URL connection
* @throws IOException if connection creation fails
*/
HttpURLConnection getConnection(URL url) throws IOException;
/**
* Create HTTP connection for the given URL with proxy
* @param url target URL for connection
* @param proxy proxy for connection
* @return HTTP URL connection
* @throws IOException if connection creation fails
*/
default HttpURLConnection getConnection(URL url, Proxy proxy) throws IOException {
return getConnection(url);
}
}Usage Examples:
import org.glassfish.jersey.client.HttpUrlConnectorProvider;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.Proxy;
// Custom connection factory
HttpUrlConnectorProvider.ConnectionFactory customFactory = new HttpUrlConnectorProvider.ConnectionFactory() {
@Override
public HttpURLConnection getConnection(URL url) throws IOException {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(10000);
connection.setReadTimeout(30000);
return connection;
}
@Override
public HttpURLConnection getConnection(URL url, Proxy proxy) throws IOException {
HttpURLConnection connection = (HttpURLConnection) url.openConnection(proxy);
connection.setConnectTimeout(10000);
connection.setReadTimeout(30000);
return connection;
}
};
// Configure client with custom connector
HttpUrlConnectorProvider connectorProvider = new HttpUrlConnectorProvider()
.connectionFactory(customFactory)
.chunkSize(8192)
.useFixedLengthStreaming();
ClientConfig config = new ClientConfig();
config.connectorProvider(connectorProvider);
Client client = JerseyClientBuilder.createClient(config);Caching wrapper for connector providers that reuses connector instances for improved performance.
public class CachingConnectorProvider implements ConnectorProvider {
/**
* Create caching wrapper for the given connector provider
* @param delegate underlying connector provider to cache
*/
public CachingConnectorProvider(ConnectorProvider delegate);
/**
* Get connector instance (cached if previously created)
* @param client client instance
* @param runtimeConfig runtime configuration
* @return cached or new connector instance
*/
public Connector getConnector(Client client, Configuration runtimeConfig);
}Usage Examples:
// Wrap any connector provider with caching
ConnectorProvider baseProvider = new HttpUrlConnectorProvider();
ConnectorProvider cachingProvider = new CachingConnectorProvider(baseProvider);
ClientConfig config = new ClientConfig();
config.connectorProvider(cachingProvider);
Client client = JerseyClientBuilder.createClient(config);Listener interface for intercepting client builder creation events.
/**
* Listener for client builder creation events
*/
public interface ClientBuilderListener {
/**
* Called when a new client builder is created
* @param builder newly created client builder
*/
void onNewBuilder(ClientBuilder builder);
}Listener interface for intercepting invocation builder creation events.
/**
* Listener for invocation builder creation events
*/
public interface InvocationBuilderListener {
/**
* Called when a new invocation builder is created
* @param builder newly created invocation builder
* @param config configuration associated with the builder
*/
void onNewBuilder(Invocation.Builder builder, Configuration config);
}Interceptor interface for processing requests before they are executed.
/**
* Interceptor for pre-request processing
*/
public interface PreInvocationInterceptor {
/**
* Called before request execution
* @param requestContext client request context for modification
*/
void beforeRequest(ClientRequestContext requestContext);
}Interceptor interface for processing requests after they are executed or when exceptions occur.
/**
* Interceptor for post-request processing
*/
public interface PostInvocationInterceptor {
/**
* Called after successful request execution
* @param requestContext client request context
* @param responseContext client response context
*/
void afterRequest(ClientRequestContext requestContext, ClientResponseContext responseContext);
/**
* Called when request execution fails with exception
* @param requestContext client request context
* @param exceptionContext exception context with failure details
*/
void onException(ClientRequestContext requestContext, ExceptionContext exceptionContext);
}Usage Examples:
// Custom pre-invocation interceptor for logging
public class LoggingPreInterceptor implements PreInvocationInterceptor {
@Override
public void beforeRequest(ClientRequestContext requestContext) {
System.out.println("Executing request: " +
requestContext.getMethod() + " " + requestContext.getUri());
// Add custom headers
requestContext.getHeaders().add("X-Request-ID", generateRequestId());
requestContext.getHeaders().add("X-Client-Version", "1.0.0");
}
}
// Custom post-invocation interceptor for metrics
public class MetricsPostInterceptor implements PostInvocationInterceptor {
@Override
public void afterRequest(ClientRequestContext requestContext,
ClientResponseContext responseContext) {
long duration = System.currentTimeMillis() - getRequestStartTime(requestContext);
recordMetrics(requestContext.getMethod(),
responseContext.getStatus(),
duration);
}
@Override
public void onException(ClientRequestContext requestContext,
ExceptionContext exceptionContext) {
recordFailure(requestContext.getMethod(),
exceptionContext.getThrowable().getClass().getSimpleName());
}
}
// Register interceptors with client
Client client = JerseyClientBuilder.createClient()
.register(new LoggingPreInterceptor())
.register(new MetricsPostInterceptor());Example of implementing a custom connector for specialized HTTP transport needs.
Usage Examples:
// Custom connector implementation
public class CustomHttpConnector implements Connector {
private final String name;
private final HttpClient httpClient; // Your preferred HTTP client
public CustomHttpConnector(String name, HttpClient httpClient) {
this.name = name;
this.httpClient = httpClient;
}
@Override
public ClientResponse apply(ClientRequest request) {
try {
// Convert Jersey ClientRequest to your HTTP client request
HttpRequest httpRequest = convertRequest(request);
// Execute request
HttpResponse httpResponse = httpClient.execute(httpRequest);
// Convert response back to Jersey ClientResponse
return convertResponse(httpResponse);
} catch (Exception e) {
throw new ProcessingException("Request execution failed", e);
}
}
@Override
public Future<?> apply(ClientRequest request, AsyncConnectorCallback callback) {
return CompletableFuture.runAsync(() -> {
try {
ClientResponse response = apply(request);
callback.response(response);
} catch (Exception e) {
callback.failure(e);
}
});
}
@Override
public String getName() {
return name;
}
@Override
public void close() {
if (httpClient != null) {
httpClient.close();
}
}
private HttpRequest convertRequest(ClientRequest clientRequest) {
// Implementation details for request conversion
return null;
}
private ClientResponse convertResponse(HttpResponse httpResponse) {
// Implementation details for response conversion
return null;
}
}
// Custom connector provider
public class CustomHttpConnectorProvider implements ConnectorProvider {
private final HttpClient httpClient;
public CustomHttpConnectorProvider(HttpClient httpClient) {
this.httpClient = httpClient;
}
@Override
public Connector getConnector(Client client, Configuration runtimeConfig) {
return new CustomHttpConnector("custom-http", httpClient);
}
}
// Use custom connector
HttpClient customHttpClient = createCustomHttpClient();
ConnectorProvider customProvider = new CustomHttpConnectorProvider(customHttpClient);
ClientConfig config = new ClientConfig();
config.connectorProvider(customProvider);
Client client = JerseyClientBuilder.createClient(config);Integration with Java's ServiceLoader mechanism for automatic discovery of SPI implementations.
Usage Examples:
// Service provider configuration (META-INF/services/org.glassfish.jersey.client.spi.ConnectorProvider)
// com.example.MyCustomConnectorProvider
// Automatic discovery and ranking
public class MyCustomConnectorProvider implements ConnectorProvider {
@Override
public Connector getConnector(Client client, Configuration runtimeConfig) {
return new MyCustomConnector();
}
}
// SPI implementations are automatically discovered and can be ranked using @Priority
@Priority(Priorities.USER)
public class HighPriorityConnectorProvider implements ConnectorProvider {
// Higher priority implementation
}
// Client will automatically use discovered implementations based on priority
Client client = JerseyClientBuilder.createClient(); // Uses discovered providersInstall with Tessl CLI
npx tessl i tessl/maven-org-glassfish-jersey-core--jersey-client