Skip to content

Commit 1f237fc

Browse files
authored
Merge pull request #592 from maxmind/horgh/http-client
Add httpClient() method to WebServiceClient.Builder
2 parents 4f6b400 + d9460a5 commit 1f237fc

File tree

3 files changed

+103
-6
lines changed

3 files changed

+103
-6
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
CHANGELOG
22
=========
33

4+
4.4.0
5+
------------------
6+
7+
* `WebServiceClient.Builder` now has an `httpClient()` method to allow
8+
passing in a custom `HttpClient`.
9+
410
4.3.1 (2025-05-28)
511
------------------
612

src/main/java/com/maxmind/geoip2/WebServiceClient.java

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,15 @@ private WebServiceClient(Builder builder) {
140140
.build();
141141

142142
requestTimeout = builder.requestTimeout;
143-
httpClient = HttpClient.newBuilder()
144-
.connectTimeout(builder.connectTimeout)
145-
.proxy(builder.proxy)
146-
.build();
143+
144+
if (builder.httpClient != null) {
145+
httpClient = builder.httpClient;
146+
} else {
147+
httpClient = HttpClient.newBuilder()
148+
.connectTimeout(builder.connectTimeout)
149+
.proxy(builder.proxy)
150+
.build();
151+
}
147152
}
148153

149154
/**
@@ -171,11 +176,12 @@ public static final class Builder {
171176
int port = 443;
172177
boolean useHttps = true;
173178

174-
Duration connectTimeout = Duration.ofSeconds(3);
179+
Duration connectTimeout = null;
175180
Duration requestTimeout = Duration.ofSeconds(20);
176181

177182
List<String> locales = Collections.singletonList("en");
178-
private ProxySelector proxy = ProxySelector.getDefault();
183+
private ProxySelector proxy = null;
184+
private HttpClient httpClient = null;
179185

180186
/**
181187
* @param accountId Your MaxMind account ID.
@@ -296,11 +302,43 @@ public Builder proxy(ProxySelector val) {
296302
return this;
297303
}
298304

305+
/**
306+
* @param val the custom HttpClient to use for requests. When providing a
307+
* custom HttpClient, you cannot also set connectTimeout or proxy
308+
* parameters as these should be configured on the provided client.
309+
* @return Builder object
310+
*/
311+
public Builder httpClient(HttpClient val) {
312+
this.httpClient = val;
313+
return this;
314+
}
315+
299316
/**
300317
* @return an instance of {@code WebServiceClient} created from the
301318
* fields set on this builder.
319+
* @throws IllegalArgumentException if httpClient is provided along with
320+
* connectTimeout or proxy settings
302321
*/
303322
public WebServiceClient build() {
323+
if (httpClient != null) {
324+
if (connectTimeout != null) {
325+
throw new IllegalArgumentException(
326+
"Cannot set both httpClient and connectTimeout. "
327+
+ "Configure timeout on the provided HttpClient instead.");
328+
}
329+
if (proxy != null) {
330+
throw new IllegalArgumentException(
331+
"Cannot set both httpClient and proxy. "
332+
+ "Configure proxy on the provided HttpClient instead.");
333+
}
334+
} else {
335+
if (connectTimeout == null) {
336+
connectTimeout = Duration.ofSeconds(3);
337+
}
338+
if (proxy == null) {
339+
proxy = ProxySelector.getDefault();
340+
}
341+
}
304342
return new WebServiceClient(this);
305343
}
306344
}

src/test/java/com/maxmind/geoip2/WebServiceClientTest.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@
3636
import com.maxmind.geoip2.record.Traits;
3737
import java.io.UnsupportedEncodingException;
3838
import java.net.InetAddress;
39+
import java.net.InetSocketAddress;
40+
import java.net.ProxySelector;
41+
import java.net.http.HttpClient;
3942
import java.nio.charset.StandardCharsets;
43+
import java.time.Duration;
4044
import java.util.List;
4145
import org.hamcrest.CoreMatchers;
4246
import org.junit.jupiter.api.Test;
@@ -407,4 +411,53 @@ private WebServiceClient createClient(String service, String ip, int status, Str
407411
.disableHttps()
408412
.build();
409413
}
414+
415+
@Test
416+
public void testHttpClientWithConnectTimeoutThrowsException() {
417+
HttpClient customClient = HttpClient.newBuilder()
418+
.connectTimeout(Duration.ofSeconds(10))
419+
.build();
420+
421+
WebServiceClient.Builder builder = new WebServiceClient.Builder(6, "0123456789")
422+
.httpClient(customClient)
423+
.connectTimeout(Duration.ofSeconds(5));
424+
425+
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, builder::build);
426+
assertEquals("Cannot set both httpClient and connectTimeout. Configure timeout on the provided HttpClient instead.",
427+
ex.getMessage());
428+
}
429+
430+
@Test
431+
public void testHttpClientWithProxyThrowsException() {
432+
HttpClient customClient = HttpClient.newBuilder()
433+
.connectTimeout(Duration.ofSeconds(10))
434+
.build();
435+
436+
ProxySelector proxySelector = ProxySelector.of(new InetSocketAddress("proxy.example.com", 8080));
437+
WebServiceClient.Builder builder = new WebServiceClient.Builder(6, "0123456789")
438+
.httpClient(customClient)
439+
.proxy(proxySelector);
440+
441+
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, builder::build);
442+
assertEquals("Cannot set both httpClient and proxy. Configure proxy on the provided HttpClient instead.",
443+
ex.getMessage());
444+
}
445+
446+
@Test
447+
public void testHttpClientWithDefaultSettingsDoesNotThrow() throws Exception {
448+
HttpClient customClient = HttpClient.newBuilder()
449+
.connectTimeout(Duration.ofSeconds(10))
450+
.build();
451+
452+
// Should not throw because we're not setting connectTimeout or proxy
453+
WebServiceClient client = new WebServiceClient.Builder(6, "0123456789")
454+
.host("localhost")
455+
.port(8080)
456+
.disableHttps()
457+
.httpClient(customClient)
458+
.build();
459+
460+
assertNotNull(client);
461+
}
462+
410463
}

0 commit comments

Comments
 (0)