-
Couldn't load subscription status.
- Fork 208
Modernization changes for new major version #620
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
oschwald
commented
Oct 14, 2025
- Move model and record classes to records
- Deprecate get methods in non-record classes*
09437e4 to
98265c6
Compare
This will eventually reduce boilerplate and provide a more consistent experience for users. I am leaving the old getter methods as deprecated for one major version to give users the ability to upgrade before having to migrate to the updated accessors. There are other breaking changes, but these will likely not affect most users.
Public getter methods in non-record classes (DatabaseReader, exception classes) have been renamed to follow the same naming convention as records (e.g., metadata() instead of getMetadata()). The old getter methods are still available but have been deprecated and will be removed in version 6.0.0. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Bump maxmind-db dependency from 3.2.0 to 4.0.0-SNAPSHOT - Update method calls to use record-style accessors instead of deprecated JavaBean-style getters in DatabaseReader.java and test files - Changes include: getDatabaseType() → databaseType(), getData() → data(), getNetwork() → network(), getNetworkAddress() → networkAddress(), getPrefixLength() → prefixLength() 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
With maxmind-db 4.0.0, records automatically use their canonical constructor for deserialization when no constructor is explicitly annotated with @MaxMindDbConstructor. This change removes the annotation from most records in the codebase. Changes: - Removed empty canonical constructors from records with no logic - Removed @MaxMindDbConstructor from canonical constructors with immutability/validation logic, relying on automatic detection - Added useDefault=true to boolean parameters to leverage automatic null-to-false conversion instead of manual Boolean→boolean handling - Kept @MaxMindDbConstructor only for records requiring custom type conversions (String→LocalDate in AnonymousPlusResponse, String→enum in ConnectionTypeResponse and Traits) - Removed unused MaxMindDbConstructor imports All tests pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Remove copy constructors from model classes that only populated IP address and network (AnonymousIpResponse, AnonymousPlusResponse, ConnectionTypeResponse, AsnResponse, DomainResponse, IspResponse, IpRiskResponse) - Update DatabaseReader getter methods to return responses directly - Update annotations to use @MaxMindDbIpAddress and @MaxMindDbNetwork for context injection - Remove @MaxMindDbConstructor from Traits that was only needed for ConnectionType conversion - Add @MaxMindDbCreator to ConnectionType.fromString() for enum deserialization These constructors are no longer needed since IP address and network are now automatically injected via @MaxMindDbIpAddress and @MaxMindDbNetwork annotations, and enum conversion is handled by @MaxMindDbCreator. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
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]>
Changed the ipAddress field type from String to InetAddress across all model and record classes. This provides better type safety and makes it clear that these fields contain IP addresses. Key changes: - Updated ipAddress field type to InetAddress in all response/record classes - Deprecated getIpAddress() methods now call ipAddress().getHostAddress() to maintain backward compatibility (still return String) - Created InetAddressSerializer to serialize InetAddress to String in JSON - Created InetAddressDeserializer to deserialize JSON strings to InetAddress - Created InetAddressModule and registered it globally in JsonSerializable - Updated all tests to call .getHostAddress() when comparing IP addresses The new ipAddress() accessor returns InetAddress, while the deprecated getIpAddress() continues to return String for backward compatibility. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
937eb39 to
f5299b9
Compare
Corrected typos and style inconsistencies in deprecated getter javadocs to match the param documentation: - MaxMind: "queried" → "queries" - Subdivision.getConfidence(): "This is a value" → "A value" - Subdivision.getIsoCode(): "contain" → "containing", "3166-2code" → "3166-2 code" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
34c6399 to
f062349
Compare
This enables Maven to resolve snapshot dependencies from the Central Portal. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
04cea6f to
9d5369d
Compare
This modernizes the codebase by using Java's var keyword for local variables where the type is obvious from the initializer. This includes: - Local variable declarations with initializers - Enhanced for-loop variables - Try-with-resources variables Some try-block variables were refactored into helper methods to enable var usage (parsePrefixLength in NetworkDeserializer and readBody in WebServiceClient). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Modernize the error code handling in handleErrorWithJsonBody() to use a switch expression instead of the traditional switch statement. This makes the code more concise and aligns with the style already used in ConnectionTypeResponse. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Use the more idiomatic String.isEmpty() method instead of comparing against an empty string literal. This expresses the intent more clearly and is the standard Java convention for empty string checks. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Replace the manual isEmpty() check and get() pattern with the more
functional and concise orElseThrow() method. This eliminates 30 lines
of boilerplate code across 10 lookup methods while maintaining the
exact same behavior.
Before:
var r = tryCountry(ipAddress);
if (r.isEmpty()) {
throw new AddressNotFoundException(...);
}
return r.get();
After:
return tryCountry(ipAddress).orElseThrow(() ->
new AddressNotFoundException(...));
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
Make GeoIp2Exception a sealed class with an explicit permits clause listing all allowed subclasses. This provides: - Explicit API stability guarantees - new exception types cannot be added externally - Compiler-enforced exhaustiveness checking for pattern matching in future Java versions - Clear documentation of the complete exception hierarchy All subclasses (AddressNotFoundException, AuthenticationException, InvalidRequestException, OutOfQueriesException, and PermissionRequiredException) were already marked as final, making them compatible with the sealed parent. Note: HttpException extends IOException, not GeoIp2Exception, so it remains outside this sealed hierarchy. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR modernizes the codebase for a new major version (5.0.0) by converting model and record classes to Java records and deprecating getter methods in favor of record-style accessor methods.
Key Changes:
- Converted all model and record classes from traditional classes to Java records
- Deprecated
get*methods throughout the codebase in favor of record accessor methods (e.g.,city()instead ofgetCity()) - Replaced abstract base classes with interfaces (
JsonSerializable,NamedRecord)
Reviewed Changes
Copilot reviewed 47 out of 47 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
src/main/java/com/maxmind/geoip2/record/*.java |
Converted record classes (City, Country, Continent, etc.) from classes to records |
src/main/java/com/maxmind/geoip2/model/*.java |
Converted model classes (CityResponse, CountryResponse, etc.) from classes to records |
src/main/java/com/maxmind/geoip2/exception/*.java |
Added new accessor methods and deprecated getters |
src/main/java/com/maxmind/geoip2/*.java |
Added new interfaces and modules for JSON serialization |
src/test/java/**/*.java |
Updated tests to use new accessor methods |
pom.xml |
Updated version to 5.0.0-SNAPSHOT and dependencies |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| traits.getStaticIpScore() | ||
| ); | ||
| public Traits() { | ||
| this(null, null, (ConnectionType) null, null, |
Copilot
AI
Oct 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The explicit (ConnectionType) null cast is unnecessary. The compiler can infer the type from the parameter. Consider removing the cast for cleaner code.
| this(null, null, (ConnectionType) null, null, | |
| this(null, null, null, null, |