Problem description
Problem
The RDF4J HTTP client stack (rdf4j-http-client) is tightly coupled to Apache HttpComponents 4 (AHC4). AHC4 types appear directly in public APIs:
HttpClientDependent#getHttpClient() / #setHttpClient() — typed to org.apache.http.client.HttpClient
HttpClientSessionManager#getHttpClient() — same
This makes it impossible for users to substitute a different HTTP client without patching RDF4J internals, and forces an AHC4 transitive dependency on all RDF4J HTTP users.
Proposed Solution
Introduce a thin, zero-third-party-dependency SPI layer (rdf4j-http-client-api) and ship two pluggable implementations:
rdf4j-http-client-jdk — backed by java.net.http.HttpClient (JDK 11+, zero additional dependencies, default)
rdf4j-http-client-apache5 — backed by Apache HttpComponents 5 (opt-in for advanced connection management)
Implementations are discovered via ServiceLoader. The active factory can be selected via the system property rdf4j.http.client.factory.
New module structure
core/http/
├── client-api/ (NEW) — SPI interfaces, no HTTP library dependency
├── client-jdk/ (NEW) — JDK java.net.http implementation
├── client-apache5/ (NEW) — Apache HC5 implementation
└── client/ (refactored) — SPARQLProtocolSession etc., depends on client-api only
Core SPI types (org.eclipse.rdf4j.http.client.spi)
| Type |
Role |
RDF4JHttpClient |
Central execution interface; execute(HttpClientRequest) → HttpClientResponse |
HttpClientRequest |
Immutable request value object (method, URI, headers, optional body) |
HttpClientResponse |
Response with status, headers, streaming body; must be closed |
HttpClientRequestBody |
Body abstraction with convenience factories (form data, string, bytes, stream) |
HttpClientConfig |
Timeouts, connection pool limits, redirect policy, TLS |
HttpAuthConfig / BasicHttpAuthConfig |
Authentication configuration (extensible) |
RDF4JHttpClientFactory |
SPI for creating clients; registered via ServiceLoader |
RDF4JHttpClients |
Utility for obtaining the default or named factory |
Refactoring scope
HttpClientDependent and HttpClientSessionManager updated to expose RDF4JHttpClient instead of AHC4 types
SPARQLProtocolSession and RDF4JProtocolSession rewritten to use RDF4JHttpClient exclusively
SharedHttpClientSessionManager updated to use RDF4JHttpClientFactory
- All existing system properties preserved (mapped to
HttpClientConfig fields)
- AHC4 dependency removed from
rdf4j-http-client entirely
Breaking Change
This is a hard break from AHC4 — no compatibility bridge. Users who inject a custom HttpClient or cast getHttpClient() to an AHC4 type must migrate:
| Current |
Migration |
repo.setHttpClient(myApacheHC4Client) |
Build an RDF4JHttpClient via RDF4JHttpClients factory |
(CloseableHttpClient) repo.getHttpClient() |
Use repo.getHttpClient() typed as RDF4JHttpClient |
Custom HttpClientSessionManager impl |
Update to new interface signature |
| Implicit AHC4 transitive dependency |
Add rdf4j-http-client-apache5 explicitly if AHC5 is desired |
Implementation Checklist
Preferred solution
No response
Are you interested in contributing a solution yourself?
None
Alternatives you've considered
No response
Anything else?
No response
Problem description
Problem
The RDF4J HTTP client stack (
rdf4j-http-client) is tightly coupled to Apache HttpComponents 4 (AHC4). AHC4 types appear directly in public APIs:HttpClientDependent#getHttpClient()/#setHttpClient()— typed toorg.apache.http.client.HttpClientHttpClientSessionManager#getHttpClient()— sameThis makes it impossible for users to substitute a different HTTP client without patching RDF4J internals, and forces an AHC4 transitive dependency on all RDF4J HTTP users.
Proposed Solution
Introduce a thin, zero-third-party-dependency SPI layer (
rdf4j-http-client-api) and ship two pluggable implementations:rdf4j-http-client-jdk— backed byjava.net.http.HttpClient(JDK 11+, zero additional dependencies, default)rdf4j-http-client-apache5— backed by Apache HttpComponents 5 (opt-in for advanced connection management)Implementations are discovered via
ServiceLoader. The active factory can be selected via the system propertyrdf4j.http.client.factory.New module structure
core/http/
├── client-api/ (NEW) — SPI interfaces, no HTTP library dependency
├── client-jdk/ (NEW) — JDK java.net.http implementation
├── client-apache5/ (NEW) — Apache HC5 implementation
└── client/ (refactored) — SPARQLProtocolSession etc., depends on client-api only
Core SPI types (
org.eclipse.rdf4j.http.client.spi)RDF4JHttpClientexecute(HttpClientRequest) → HttpClientResponseHttpClientRequestHttpClientResponseHttpClientRequestBodyHttpClientConfigHttpAuthConfig/BasicHttpAuthConfigRDF4JHttpClientFactoryServiceLoaderRDF4JHttpClientsRefactoring scope
HttpClientDependentandHttpClientSessionManagerupdated to exposeRDF4JHttpClientinstead of AHC4 typesSPARQLProtocolSessionandRDF4JProtocolSessionrewritten to useRDF4JHttpClientexclusivelySharedHttpClientSessionManagerupdated to useRDF4JHttpClientFactoryHttpClientConfigfields)rdf4j-http-cliententirelyBreaking Change
This is a hard break from AHC4 — no compatibility bridge. Users who inject a custom
HttpClientor castgetHttpClient()to an AHC4 type must migrate:repo.setHttpClient(myApacheHC4Client)RDF4JHttpClientviaRDF4JHttpClientsfactory(CloseableHttpClient) repo.getHttpClient()repo.getHttpClient()typed asRDF4JHttpClientHttpClientSessionManagerimplrdf4j-http-client-apache5explicitly if AHC5 is desiredImplementation Checklist
rdf4j-http-client-apiwith all SPI interfaces and value typesrdf4j-http-client-jdk(JDK 11+ implementation)rdf4j-http-client-apache5(AHC5 implementation)SPARQLProtocolSessionandRDF4JProtocolSessionSharedHttpClientSessionManagerHttpClientDependentandHttpClientSessionManagerinterfacesrdf4j-http-clientpom.xmlPreferred solution
No response
Are you interested in contributing a solution yourself?
None
Alternatives you've considered
No response
Anything else?
No response