What Changed When Upgrading Apache HttpClient 4 to 5? A Hands‑On Migration Guide
This article walks through the painful migration from Apache HttpClient 4.x to 5.3, detailing modular design, customization, HTTP/2 support, connection management, API changes such as retry strategy, request/response configuration, interceptors, async client, and provides concrete Maven snippets and code comparisons to help developers evaluate whether the upgrade is worthwhile.
Introduction
The author upgraded a project from Apache HttpClient 4.x to 5.3 and documents the migration experience, highlighting both the new features of HttpClient 5 and the practical difficulties encountered.
Key Benefits of HttpClient 5
Modular design that lets users include only required modules.
Extensive configurability for connection management, timeouts, proxies, and security policies.
Built‑in asynchronous request support for higher concurrency.
Improved connection pool handling with flexible reuse and TTL settings.
Native HTTP/2 support, alongside full HTTP/1.1 and TLS/SSL compatibility.
Updated code structure and performance optimizations.
Simpler, more intuitive API.
In practice, the author found only modest gains, with the main attraction being HTTP/2 support, which they have not yet tested.
Maven Dependency
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3</version>
</dependency>When other libraries still depend on HttpClient 4.x, the old version must be excluded to avoid conflicts.
Package Name Change
All classes now start with org.apache.hc.client5., requiring extensive refactoring of import statements.
Retry Strategy API
Old interface HttpRequestRetryHandler is replaced by HttpRequestRetryStrategy. The new strategy requires implementing three methods:
public boolean retryRequest(HttpRequest request, IOException exception, int execCount, HttpContext context)
public boolean retryRequest(HttpResponse response, int execCount, HttpContext context)
public TimeValue getRetryInterval(HttpResponse response, int execCount, HttpContext context)The first method maps closely to the old one; the second allows response‑based retry decisions, and the third provides a configurable back‑off interval using org.apache.hc.core5.util.TimeValue.
Connection Configuration
Old code used a custom ConnectionConfig builder with charset and message constraints. The new version adds explicit timeout settings:
ConnectionConfig connectionConfig = ConnectionConfig.custom()
.setConnectTimeout(Timeout.of(Duration.ofMillis(CONNECT_TIMEOUT)))
.setSocketTimeout(Timeout.of(Duration.ofMillis(SOCKET_TIMEOUT)))
.setTimeToLive(Timeout.of(Duration.ofMillis(MAX_ACCEPT_TIME)))
.setValidateAfterInactivity(Timeout.of(Duration.ofMillis(MAX_ACCEPT_TIME)))
.build();The functional differences are minor; the extra timeout options are rarely needed for typical performance tests.
Connection Pool Manager
Creation of PoolingHttpClientConnectionManager now prefers a builder pattern. The old code manually built a Registry<ConnectionSocketFactory> for HTTP and HTTPS. The new builder registers default socket factories automatically, reducing boilerplate.
PoolingHttpClientConnectionManager poolingMgr = new PoolingHttpClientConnectionManager(
RegistryBuilder.create()
.register(URIScheme.HTTP.id, PlainConnectionSocketFactory.getSocketFactory())
.register(URIScheme.HTTPS.id, this.sslSocketFactory != null ? this.sslSocketFactory :
(this.systemProperties ? SSLConnectionSocketFactory.getSystemSocketFactory() : SSLConnectionSocketFactory.getSocketFactory()))
.build(),
this.poolConcurrencyPolicy,
this.poolReusePolicy,
null,
this.schemePortResolver,
this.dnsResolver,
this.connectionFactory);The async pool manager adds a BasicClientTlsStrategy via .setTlsStrategy(...).
Request Configuration
Many duplicate connection settings were removed. The new request config example sets timeouts, disables redirects, and uses a string for the cookie spec because the enum was removed:
private static RequestConfig getRequestConfig() {
return RequestConfig.custom()
.setConnectionRequestTimeout(Timeout.ofMilliseconds(CONNECT_REQUEST_TIMEOUT))
.setCookieSpec("ignoreCookies")
.setRedirectsEnabled(false)
.build();
}HttpClient Builder
To disable cookie management, the new builder method disableCookieManagement() is used, effectively removing the default CookieStore handling.
Interceptor Signature Change
The process method now receives an additional EntityDetails argument:
public void process(HttpResponse response, EntityDetails entityDetails, HttpContext context)Resource Cleanup
Old methods closeExpiredConnections() and closeIdleConnections(...) are replaced by the shorter closeExpired() and closeIdle(TimeValue.ofSeconds(...)).
Async Client Start Logic
The state enum changed from INACTIVE/ACTIVE to READY/RUNNING, and the start method now submits the reactor to an executor service instead of directly starting a thread.
Proxy Configuration
Proxy setup moved from a direct setProxy call on the client to being configured via RequestConfig, but the code snippet remains the same:
setProxy(new HttpHost(ip, port))Class Name Changes
Many classes now carry the classic prefix, e.g., org.apache.hc.core5.http.message.BasicClassicHttpRequest and org.apache.hc.core5.http.ClassicHttpResponse. Request classes live under org.apache.hc.client5.http.classic.methods.
Entity Interface Update
Requests/responses now implement org.apache.hc.core5.http.HttpEntityContainer instead of the old org.apache.http.HttpEntityEnclosingRequest. The method boolean expectContinue() was removed.
Full Entity Support for GET/DELETE
Unlike the previous version where GET and DELETE could not carry a body, HttpClient 5 allows entities on all request methods.
Setting Entity Encoding
The API now accepts a java.nio.charset.Charset directly, simplifying character‑set handling.
Header Retrieval
The method name changed from getAllHeader to getHeaders.
Response Line Access
The removed getStatusLine is replaced by CloseableHttpResponse#getCode to obtain the status code.
URI Access
Old getURI returned a URI object; the new getUri does the same, while getRequestUri returns a String. The change appears to be a naming convention adjustment.
Async Request API
New async request classes such as org.apache.hc.client5.http.async.methods.SimpleHttpRequest and SimpleHttpResponse are introduced. Both sync and async clients provide a copy() method, though the request copy is marked deprecated.
Conclusion
The migration required extensive code changes, especially around package names, retry strategy, connection management, and request/response classes. While HttpClient 5 offers modularity, HTTP/2 support, and cleaner APIs, the author recommends upgrading only when those features are needed, as the overall performance gain was not significant for their use case.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
