Skip to content

Commit 99b2ec2

Browse files
oschwaldclaude
andcommitted
Use generics to eliminate redundant private getX methods
All the private getX methods in DatabaseReader followed similar patterns, so we've consolidated them into a single generic getResponse() method. For responses that need locale transformations (City, Country, Enterprise), we use Optional.map() to apply the transformation. This also changes the get() method to accept an explicit caller parameter instead of introspecting the stack trace, making error messages clearer and more reliable. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 89dad0f commit 99b2ec2

File tree

1 file changed

+61
-162
lines changed

1 file changed

+61
-162
lines changed

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

Lines changed: 61 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -244,16 +244,15 @@ static record LookupResult<T>(T model, String ipAddress, Network network) {
244244
* @param ipAddress IPv4 or IPv6 address to lookup.
245245
* @param cls The class to deserialize to.
246246
* @param expectedType The expected database type.
247+
* @param caller The name of the public method calling this (for error messages).
247248
* @return A {@code LookupResult<T>} object with the data for the IP address
248249
* @throws IOException if there is an error opening or reading from the file.
249250
*/
250251
private <T> LookupResult<T> get(InetAddress ipAddress, Class<T> cls,
251-
DatabaseType expectedType)
252+
DatabaseType expectedType, String caller)
252253
throws IOException {
253254

254255
if ((databaseType & expectedType.type) == 0) {
255-
String caller = Thread.currentThread().getStackTrace()[3]
256-
.getMethodName();
257256
throw new UnsupportedOperationException(
258257
"Invalid attempt to open a " + metadata().databaseType()
259258
+ " database using the " + caller + " method");
@@ -266,6 +265,30 @@ private <T> LookupResult<T> get(InetAddress ipAddress, Class<T> cls,
266265
return new LookupResult<>(o, ipAddress.getHostAddress(), record.network());
267266
}
268267

268+
/**
269+
* Generic method to get a response.
270+
*
271+
* @param ipAddress IPv4 or IPv6 address to lookup.
272+
* @param cls The class to deserialize to.
273+
* @param expectedType The expected database type.
274+
* @param caller The name of the public method calling this (for error messages).
275+
* @return An Optional containing the response, or empty if not found
276+
* @throws IOException if there is an error opening or reading from the file.
277+
*/
278+
private <T> Optional<T> getResponse(
279+
InetAddress ipAddress,
280+
Class<T> cls,
281+
DatabaseType expectedType,
282+
String caller
283+
) throws IOException {
284+
LookupResult<T> result = this.get(ipAddress, cls, expectedType, caller);
285+
T response = result.model();
286+
if (response == null) {
287+
return Optional.empty();
288+
}
289+
return Optional.of(response);
290+
}
291+
269292
/**
270293
* <p>
271294
* Closes the database.
@@ -288,7 +311,7 @@ public void close() throws IOException {
288311
@Override
289312
public CountryResponse country(InetAddress ipAddress) throws IOException,
290313
GeoIp2Exception {
291-
Optional<CountryResponse> r = getCountry(ipAddress);
314+
Optional<CountryResponse> r = tryCountry(ipAddress);
292315
if (r.isEmpty()) {
293316
throw new AddressNotFoundException("The address "
294317
+ ipAddress.getHostAddress() + " is not in the database.");
@@ -299,33 +322,19 @@ public CountryResponse country(InetAddress ipAddress) throws IOException,
299322
@Override
300323
public Optional<CountryResponse> tryCountry(InetAddress ipAddress) throws IOException,
301324
GeoIp2Exception {
302-
return getCountry(ipAddress);
303-
}
304-
305-
private Optional<CountryResponse> getCountry(
306-
InetAddress ipAddress
307-
) throws IOException, GeoIp2Exception {
308-
LookupResult<CountryResponse> result = this.get(
325+
Optional<CountryResponse> response = getResponse(
309326
ipAddress,
310327
CountryResponse.class,
311-
DatabaseType.COUNTRY
312-
);
313-
CountryResponse response = result.model();
314-
if (response == null) {
315-
return Optional.empty();
316-
}
317-
return Optional.of(
318-
new CountryResponse(
319-
response,
320-
locales
321-
)
328+
DatabaseType.COUNTRY,
329+
"country"
322330
);
331+
return response.map(r -> new CountryResponse(r, locales));
323332
}
324333

325334
@Override
326335
public CityResponse city(InetAddress ipAddress) throws IOException,
327336
GeoIp2Exception {
328-
Optional<CityResponse> r = getCity(ipAddress);
337+
Optional<CityResponse> r = tryCity(ipAddress);
329338
if (r.isEmpty()) {
330339
throw new AddressNotFoundException("The address "
331340
+ ipAddress.getHostAddress() + " is not in the database.");
@@ -336,24 +345,13 @@ public CityResponse city(InetAddress ipAddress) throws IOException,
336345
@Override
337346
public Optional<CityResponse> tryCity(InetAddress ipAddress) throws IOException,
338347
GeoIp2Exception {
339-
return getCity(ipAddress);
340-
}
341-
342-
private Optional<CityResponse> getCity(
343-
InetAddress ipAddress
344-
) throws IOException, GeoIp2Exception {
345-
LookupResult<CityResponse> result = this.get(
348+
Optional<CityResponse> response = getResponse(
346349
ipAddress,
347350
CityResponse.class,
348-
DatabaseType.CITY
349-
);
350-
CityResponse response = result.model();
351-
if (response == null) {
352-
return Optional.empty();
353-
}
354-
return Optional.of(
355-
new CityResponse(response, locales)
351+
DatabaseType.CITY,
352+
"city"
356353
);
354+
return response.map(r -> new CityResponse(r, locales));
357355
}
358356

359357
/**
@@ -367,7 +365,7 @@ private Optional<CityResponse> getCity(
367365
@Override
368366
public AnonymousIpResponse anonymousIp(InetAddress ipAddress) throws IOException,
369367
GeoIp2Exception {
370-
Optional<AnonymousIpResponse> r = getAnonymousIp(ipAddress);
368+
Optional<AnonymousIpResponse> r = tryAnonymousIp(ipAddress);
371369
if (r.isEmpty()) {
372370
throw new AddressNotFoundException("The address "
373371
+ ipAddress.getHostAddress() + " is not in the database.");
@@ -378,22 +376,12 @@ public AnonymousIpResponse anonymousIp(InetAddress ipAddress) throws IOException
378376
@Override
379377
public Optional<AnonymousIpResponse> tryAnonymousIp(InetAddress ipAddress) throws IOException,
380378
GeoIp2Exception {
381-
return getAnonymousIp(ipAddress);
382-
}
383-
384-
private Optional<AnonymousIpResponse> getAnonymousIp(
385-
InetAddress ipAddress
386-
) throws IOException, GeoIp2Exception {
387-
LookupResult<AnonymousIpResponse> result = this.get(
379+
return getResponse(
388380
ipAddress,
389381
AnonymousIpResponse.class,
390-
DatabaseType.ANONYMOUS_IP
382+
DatabaseType.ANONYMOUS_IP,
383+
"anonymousIp"
391384
);
392-
AnonymousIpResponse response = result.model();
393-
if (response == null) {
394-
return Optional.empty();
395-
}
396-
return Optional.of(response);
397385
}
398386

399387
/**
@@ -407,7 +395,7 @@ private Optional<AnonymousIpResponse> getAnonymousIp(
407395
@Override
408396
public AnonymousPlusResponse anonymousPlus(InetAddress ipAddress) throws IOException,
409397
GeoIp2Exception {
410-
Optional<AnonymousPlusResponse> r = getAnonymousPlus(ipAddress);
398+
Optional<AnonymousPlusResponse> r = tryAnonymousPlus(ipAddress);
411399
if (r.isEmpty()) {
412400
throw new AddressNotFoundException("The address "
413401
+ ipAddress.getHostAddress() + " is not in the database.");
@@ -419,22 +407,12 @@ public AnonymousPlusResponse anonymousPlus(InetAddress ipAddress) throws IOExcep
419407
public Optional<AnonymousPlusResponse> tryAnonymousPlus(InetAddress ipAddress)
420408
throws IOException,
421409
GeoIp2Exception {
422-
return getAnonymousPlus(ipAddress);
423-
}
424-
425-
private Optional<AnonymousPlusResponse> getAnonymousPlus(
426-
InetAddress ipAddress
427-
) throws IOException, GeoIp2Exception {
428-
LookupResult<AnonymousPlusResponse> result = this.get(
410+
return getResponse(
429411
ipAddress,
430412
AnonymousPlusResponse.class,
431-
DatabaseType.ANONYMOUS_PLUS
413+
DatabaseType.ANONYMOUS_PLUS,
414+
"anonymousPlus"
432415
);
433-
AnonymousPlusResponse response = result.model();
434-
if (response == null) {
435-
return Optional.empty();
436-
}
437-
return Optional.of(response);
438416
}
439417

440418

@@ -449,7 +427,7 @@ private Optional<AnonymousPlusResponse> getAnonymousPlus(
449427
@Override
450428
public IpRiskResponse ipRisk(InetAddress ipAddress) throws IOException,
451429
GeoIp2Exception {
452-
Optional<IpRiskResponse> r = getIpRisk(ipAddress);
430+
Optional<IpRiskResponse> r = tryIpRisk(ipAddress);
453431
if (r.isEmpty()) {
454432
throw new AddressNotFoundException("The address "
455433
+ ipAddress.getHostAddress() + " is not in the database.");
@@ -460,21 +438,7 @@ public IpRiskResponse ipRisk(InetAddress ipAddress) throws IOException,
460438
@Override
461439
public Optional<IpRiskResponse> tryIpRisk(InetAddress ipAddress) throws IOException,
462440
GeoIp2Exception {
463-
return getIpRisk(ipAddress);
464-
}
465-
466-
private Optional<IpRiskResponse> getIpRisk(InetAddress ipAddress) throws IOException,
467-
GeoIp2Exception {
468-
LookupResult<IpRiskResponse> result = this.get(
469-
ipAddress,
470-
IpRiskResponse.class,
471-
DatabaseType.IP_RISK
472-
);
473-
IpRiskResponse response = result.model();
474-
if (response == null) {
475-
return Optional.empty();
476-
}
477-
return Optional.of(response);
441+
return getResponse(ipAddress, IpRiskResponse.class, DatabaseType.IP_RISK, "ipRisk");
478442
}
479443

480444
/**
@@ -488,7 +452,7 @@ private Optional<IpRiskResponse> getIpRisk(InetAddress ipAddress) throws IOExcep
488452
@Override
489453
public AsnResponse asn(InetAddress ipAddress) throws IOException,
490454
GeoIp2Exception {
491-
Optional<AsnResponse> r = getAsn(ipAddress);
455+
Optional<AsnResponse> r = tryAsn(ipAddress);
492456
if (r.isEmpty()) {
493457
throw new AddressNotFoundException("The address "
494458
+ ipAddress.getHostAddress() + " is not in the database.");
@@ -499,21 +463,7 @@ public AsnResponse asn(InetAddress ipAddress) throws IOException,
499463
@Override
500464
public Optional<AsnResponse> tryAsn(InetAddress ipAddress) throws IOException,
501465
GeoIp2Exception {
502-
return getAsn(ipAddress);
503-
}
504-
505-
private Optional<AsnResponse> getAsn(InetAddress ipAddress)
506-
throws IOException, GeoIp2Exception {
507-
LookupResult<AsnResponse> result = this.get(
508-
ipAddress,
509-
AsnResponse.class,
510-
DatabaseType.ASN
511-
);
512-
AsnResponse response = result.model();
513-
if (response == null) {
514-
return Optional.empty();
515-
}
516-
return Optional.of(response);
466+
return getResponse(ipAddress, AsnResponse.class, DatabaseType.ASN, "asn");
517467
}
518468

519469
/**
@@ -527,7 +477,7 @@ private Optional<AsnResponse> getAsn(InetAddress ipAddress)
527477
@Override
528478
public ConnectionTypeResponse connectionType(InetAddress ipAddress)
529479
throws IOException, GeoIp2Exception {
530-
Optional<ConnectionTypeResponse> r = getConnectionType(ipAddress);
480+
Optional<ConnectionTypeResponse> r = tryConnectionType(ipAddress);
531481
if (r.isEmpty()) {
532482
throw new AddressNotFoundException("The address "
533483
+ ipAddress.getHostAddress() + " is not in the database.");
@@ -538,22 +488,12 @@ public ConnectionTypeResponse connectionType(InetAddress ipAddress)
538488
@Override
539489
public Optional<ConnectionTypeResponse> tryConnectionType(InetAddress ipAddress)
540490
throws IOException, GeoIp2Exception {
541-
return getConnectionType(ipAddress);
542-
}
543-
544-
private Optional<ConnectionTypeResponse> getConnectionType(
545-
InetAddress ipAddress
546-
) throws IOException, GeoIp2Exception {
547-
LookupResult<ConnectionTypeResponse> result = this.get(
491+
return getResponse(
548492
ipAddress,
549493
ConnectionTypeResponse.class,
550-
DatabaseType.CONNECTION_TYPE
494+
DatabaseType.CONNECTION_TYPE,
495+
"connectionType"
551496
);
552-
ConnectionTypeResponse response = result.model();
553-
if (response == null) {
554-
return Optional.empty();
555-
}
556-
return Optional.of(response);
557497
}
558498

559499
/**
@@ -567,7 +507,7 @@ private Optional<ConnectionTypeResponse> getConnectionType(
567507
@Override
568508
public DomainResponse domain(InetAddress ipAddress) throws IOException,
569509
GeoIp2Exception {
570-
Optional<DomainResponse> r = getDomain(ipAddress);
510+
Optional<DomainResponse> r = tryDomain(ipAddress);
571511
if (r.isEmpty()) {
572512
throw new AddressNotFoundException("The address "
573513
+ ipAddress.getHostAddress() + " is not in the database.");
@@ -578,22 +518,7 @@ public DomainResponse domain(InetAddress ipAddress) throws IOException,
578518
@Override
579519
public Optional<DomainResponse> tryDomain(InetAddress ipAddress) throws IOException,
580520
GeoIp2Exception {
581-
return getDomain(ipAddress);
582-
}
583-
584-
private Optional<DomainResponse> getDomain(
585-
InetAddress ipAddress
586-
) throws IOException, GeoIp2Exception {
587-
LookupResult<DomainResponse> result = this.get(
588-
ipAddress,
589-
DomainResponse.class,
590-
DatabaseType.DOMAIN
591-
);
592-
DomainResponse response = result.model();
593-
if (response == null) {
594-
return Optional.empty();
595-
}
596-
return Optional.of(response);
521+
return getResponse(ipAddress, DomainResponse.class, DatabaseType.DOMAIN, "domain");
597522
}
598523

599524
/**
@@ -607,7 +532,7 @@ private Optional<DomainResponse> getDomain(
607532
@Override
608533
public EnterpriseResponse enterprise(InetAddress ipAddress) throws IOException,
609534
GeoIp2Exception {
610-
Optional<EnterpriseResponse> r = getEnterprise(ipAddress);
535+
Optional<EnterpriseResponse> r = tryEnterprise(ipAddress);
611536
if (r.isEmpty()) {
612537
throw new AddressNotFoundException("The address "
613538
+ ipAddress.getHostAddress() + " is not in the database.");
@@ -618,24 +543,13 @@ public EnterpriseResponse enterprise(InetAddress ipAddress) throws IOException,
618543
@Override
619544
public Optional<EnterpriseResponse> tryEnterprise(InetAddress ipAddress) throws IOException,
620545
GeoIp2Exception {
621-
return getEnterprise(ipAddress);
622-
}
623-
624-
private Optional<EnterpriseResponse> getEnterprise(
625-
InetAddress ipAddress
626-
) throws IOException, GeoIp2Exception {
627-
LookupResult<EnterpriseResponse> result = this.get(
546+
Optional<EnterpriseResponse> response = getResponse(
628547
ipAddress,
629548
EnterpriseResponse.class,
630-
DatabaseType.ENTERPRISE
631-
);
632-
EnterpriseResponse response = result.model();
633-
if (response == null) {
634-
return Optional.empty();
635-
}
636-
return Optional.of(
637-
new EnterpriseResponse(response, locales)
549+
DatabaseType.ENTERPRISE,
550+
"enterprise"
638551
);
552+
return response.map(r -> new EnterpriseResponse(r, locales));
639553
}
640554

641555
/**
@@ -649,7 +563,7 @@ private Optional<EnterpriseResponse> getEnterprise(
649563
@Override
650564
public IspResponse isp(InetAddress ipAddress) throws IOException,
651565
GeoIp2Exception {
652-
Optional<IspResponse> r = getIsp(ipAddress);
566+
Optional<IspResponse> r = tryIsp(ipAddress);
653567
if (r.isEmpty()) {
654568
throw new AddressNotFoundException("The address "
655569
+ ipAddress.getHostAddress() + " is not in the database.");
@@ -660,22 +574,7 @@ public IspResponse isp(InetAddress ipAddress) throws IOException,
660574
@Override
661575
public Optional<IspResponse> tryIsp(InetAddress ipAddress) throws IOException,
662576
GeoIp2Exception {
663-
return getIsp(ipAddress);
664-
}
665-
666-
private Optional<IspResponse> getIsp(
667-
InetAddress ipAddress
668-
) throws IOException, GeoIp2Exception {
669-
LookupResult<IspResponse> result = this.get(
670-
ipAddress,
671-
IspResponse.class,
672-
DatabaseType.ISP
673-
);
674-
IspResponse response = result.model();
675-
if (response == null) {
676-
return Optional.empty();
677-
}
678-
return Optional.of(response);
577+
return getResponse(ipAddress, IspResponse.class, DatabaseType.ISP, "isp");
679578
}
680579

681580
/**

0 commit comments

Comments
 (0)