diff --git a/CHANGELOG.md b/CHANGELOG.md index b0ebb039..f182dbbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ CHANGELOG 5.0.0 ------------------ +* **BREAKING:** All model and record classes have been converted to Java records. + This provides a more modern, immutable data model with automatic implementations + of `equals()`, `hashCode()`, and `toString()`. The abstract classes + `AbstractRecord`, `AbstractNamedRecord`, `AbstractResponse`, + `AbstractCountryResponse`, `AbstractCityResponse`, and `IpBaseResponse` have + been removed. Record components can be accessed using the new accessor methods + (e.g., `city()`, `country()`, `location()`). The traditional getter methods + (e.g., `getCity()`, `getCountry()`, `getLocation()`) are still available but + have been deprecated and will be removed in version 6.0.0. +* **BREAKING:** `RepresentedCountry` is now a separate record type instead of + extending `Country`. It shares the same fields as `Country` but adds a `type` + field. * The deprecation notices for IP Risk database support have been removed. IP Risk database support will continue to be maintained. * **BREAKING:** The deprecated `WebServiceClient.Builder` methods @@ -25,6 +37,11 @@ CHANGELOG * **BREAKING:** Removed no longer necessary `JacksonInject` annotations for `ip_address`, `network`, and `traits` from several classes. The `JsonInjector` class was removed. +* Public getter methods in non-record classes (e.g., `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. 4.4.0 (2025-08-28) ------------------ diff --git a/pom.xml b/pom.xml index 585ee5aa..9afd3724 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.maxmind.geoip2 geoip2 - 4.4.0 + 5.0.0-SNAPSHOT jar MaxMind GeoIP2 API GeoIP2 webservice client and database reader @@ -36,11 +36,24 @@ goschwald@maxmind.com + + + Central Portal Snapshots + central-portal-snapshots + https://central.sonatype.com/repository/maven-snapshots/ + + false + + + true + + + com.maxmind.db maxmind-db - 3.2.0 + 4.0.0-SNAPSHOT com.fasterxml.jackson.core @@ -294,10 +307,4 @@ - - - sonatype-nexus-staging - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - diff --git a/src/main/java/com/maxmind/geoip2/DatabaseReader.java b/src/main/java/com/maxmind/geoip2/DatabaseReader.java index 1c220e1c..aedfeb2e 100644 --- a/src/main/java/com/maxmind/geoip2/DatabaseReader.java +++ b/src/main/java/com/maxmind/geoip2/DatabaseReader.java @@ -115,8 +115,8 @@ private DatabaseReader(Builder builder) throws IOException { } private int getDatabaseType() { - String databaseType = this.getMetadata().getDatabaseType(); - int type = 0; + var databaseType = this.metadata().databaseType(); + var type = 0; if (databaseType.contains("GeoIP2-Anonymous-IP")) { type |= DatabaseType.ANONYMOUS_IP.type; } @@ -244,26 +244,49 @@ static record LookupResult(T model, String ipAddress, Network network) { * @param ipAddress IPv4 or IPv6 address to lookup. * @param cls The class to deserialize to. * @param expectedType The expected database type. + * @param caller The name of the public method calling this (for error messages). * @return A {@code LookupResult} object with the data for the IP address * @throws IOException if there is an error opening or reading from the file. */ private LookupResult get(InetAddress ipAddress, Class cls, - DatabaseType expectedType) + DatabaseType expectedType, String caller) throws IOException { if ((databaseType & expectedType.type) == 0) { - String caller = Thread.currentThread().getStackTrace()[3] - .getMethodName(); throw new UnsupportedOperationException( - "Invalid attempt to open a " + getMetadata().getDatabaseType() + "Invalid attempt to open a " + metadata().databaseType() + " database using the " + caller + " method"); } - DatabaseRecord record = reader.getRecord(ipAddress, cls); + var record = reader.getRecord(ipAddress, cls); - T o = record.getData(); + var o = record.data(); - return new LookupResult<>(o, ipAddress.getHostAddress(), record.getNetwork()); + return new LookupResult<>(o, ipAddress.getHostAddress(), record.network()); + } + + /** + * Generic method to get a response. + * + * @param ipAddress IPv4 or IPv6 address to lookup. + * @param cls The class to deserialize to. + * @param expectedType The expected database type. + * @param caller The name of the public method calling this (for error messages). + * @return An Optional containing the response, or empty if not found + * @throws IOException if there is an error opening or reading from the file. + */ + private Optional getResponse( + InetAddress ipAddress, + Class cls, + DatabaseType expectedType, + String caller + ) throws IOException { + var result = this.get(ipAddress, cls, expectedType, caller); + var response = result.model(); + if (response == null) { + return Optional.empty(); + } + return Optional.of(response); } /** @@ -288,79 +311,41 @@ public void close() throws IOException { @Override public CountryResponse country(InetAddress ipAddress) throws IOException, GeoIp2Exception { - Optional r = getCountry(ipAddress); - if (r.isEmpty()) { - throw new AddressNotFoundException("The address " - + ipAddress.getHostAddress() + " is not in the database."); - } - return r.get(); + return tryCountry(ipAddress).orElseThrow(() -> + new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database.")); } @Override public Optional tryCountry(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return getCountry(ipAddress); - } - - private Optional getCountry( - InetAddress ipAddress - ) throws IOException, GeoIp2Exception { - LookupResult result = this.get( + var response = getResponse( ipAddress, CountryResponse.class, - DatabaseType.COUNTRY - ); - CountryResponse response = result.model(); - if (response == null) { - return Optional.empty(); - } - return Optional.of( - new CountryResponse( - response, - result.ipAddress(), - result.network(), - locales - ) + DatabaseType.COUNTRY, + "country" ); + return response.map(r -> new CountryResponse(r, locales)); } @Override public CityResponse city(InetAddress ipAddress) throws IOException, GeoIp2Exception { - Optional r = getCity(ipAddress); - if (r.isEmpty()) { - throw new AddressNotFoundException("The address " - + ipAddress.getHostAddress() + " is not in the database."); - } - return r.get(); + return tryCity(ipAddress).orElseThrow(() -> + new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database.")); } @Override public Optional tryCity(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return getCity(ipAddress); - } - - private Optional getCity( - InetAddress ipAddress - ) throws IOException, GeoIp2Exception { - LookupResult result = this.get( + var response = getResponse( ipAddress, CityResponse.class, - DatabaseType.CITY - ); - CityResponse response = result.model(); - if (response == null) { - return Optional.empty(); - } - return Optional.of( - new CityResponse( - response, - result.ipAddress(), - result.network(), - locales - ) + DatabaseType.CITY, + "city" ); + return response.map(r -> new CityResponse(r, locales)); } /** @@ -374,38 +359,19 @@ private Optional getCity( @Override public AnonymousIpResponse anonymousIp(InetAddress ipAddress) throws IOException, GeoIp2Exception { - Optional r = getAnonymousIp(ipAddress); - if (r.isEmpty()) { - throw new AddressNotFoundException("The address " - + ipAddress.getHostAddress() + " is not in the database."); - } - return r.get(); + return tryAnonymousIp(ipAddress).orElseThrow(() -> + new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database.")); } @Override public Optional tryAnonymousIp(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return getAnonymousIp(ipAddress); - } - - private Optional getAnonymousIp( - InetAddress ipAddress - ) throws IOException, GeoIp2Exception { - LookupResult result = this.get( + return getResponse( ipAddress, AnonymousIpResponse.class, - DatabaseType.ANONYMOUS_IP - ); - AnonymousIpResponse response = result.model(); - if (response == null) { - return Optional.empty(); - } - return Optional.of( - new AnonymousIpResponse( - response, - result.ipAddress(), - result.network() - ) + DatabaseType.ANONYMOUS_IP, + "anonymousIp" ); } @@ -420,39 +386,20 @@ private Optional getAnonymousIp( @Override public AnonymousPlusResponse anonymousPlus(InetAddress ipAddress) throws IOException, GeoIp2Exception { - Optional r = getAnonymousPlus(ipAddress); - if (r.isEmpty()) { - throw new AddressNotFoundException("The address " - + ipAddress.getHostAddress() + " is not in the database."); - } - return r.get(); + return tryAnonymousPlus(ipAddress).orElseThrow(() -> + new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database.")); } @Override public Optional tryAnonymousPlus(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return getAnonymousPlus(ipAddress); - } - - private Optional getAnonymousPlus( - InetAddress ipAddress - ) throws IOException, GeoIp2Exception { - LookupResult result = this.get( + return getResponse( ipAddress, AnonymousPlusResponse.class, - DatabaseType.ANONYMOUS_PLUS - ); - AnonymousPlusResponse response = result.model(); - if (response == null) { - return Optional.empty(); - } - return Optional.of( - new AnonymousPlusResponse( - response, - result.ipAddress(), - result.network() - ) + DatabaseType.ANONYMOUS_PLUS, + "anonymousPlus" ); } @@ -468,38 +415,15 @@ private Optional getAnonymousPlus( @Override public IpRiskResponse ipRisk(InetAddress ipAddress) throws IOException, GeoIp2Exception { - Optional r = getIpRisk(ipAddress); - if (r.isEmpty()) { - throw new AddressNotFoundException("The address " - + ipAddress.getHostAddress() + " is not in the database."); - } - return r.get(); + return tryIpRisk(ipAddress).orElseThrow(() -> + new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database.")); } @Override public Optional tryIpRisk(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return getIpRisk(ipAddress); - } - - private Optional getIpRisk(InetAddress ipAddress) throws IOException, - GeoIp2Exception { - LookupResult result = this.get( - ipAddress, - IpRiskResponse.class, - DatabaseType.IP_RISK - ); - IpRiskResponse response = result.model(); - if (response == null) { - return Optional.empty(); - } - return Optional.of( - new IpRiskResponse( - response, - result.ipAddress(), - result.network() - ) - ); + return getResponse(ipAddress, IpRiskResponse.class, DatabaseType.IP_RISK, "ipRisk"); } /** @@ -513,38 +437,15 @@ private Optional getIpRisk(InetAddress ipAddress) throws IOExcep @Override public AsnResponse asn(InetAddress ipAddress) throws IOException, GeoIp2Exception { - Optional r = getAsn(ipAddress); - if (r.isEmpty()) { - throw new AddressNotFoundException("The address " - + ipAddress.getHostAddress() + " is not in the database."); - } - return r.get(); + return tryAsn(ipAddress).orElseThrow(() -> + new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database.")); } @Override public Optional tryAsn(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return getAsn(ipAddress); - } - - private Optional getAsn(InetAddress ipAddress) - throws IOException, GeoIp2Exception { - LookupResult result = this.get( - ipAddress, - AsnResponse.class, - DatabaseType.ASN - ); - AsnResponse response = result.model(); - if (response == null) { - return Optional.empty(); - } - return Optional.of( - new AsnResponse( - response, - result.ipAddress(), - result.network() - ) - ); + return getResponse(ipAddress, AsnResponse.class, DatabaseType.ASN, "asn"); } /** @@ -558,38 +459,19 @@ private Optional getAsn(InetAddress ipAddress) @Override public ConnectionTypeResponse connectionType(InetAddress ipAddress) throws IOException, GeoIp2Exception { - Optional r = getConnectionType(ipAddress); - if (r.isEmpty()) { - throw new AddressNotFoundException("The address " - + ipAddress.getHostAddress() + " is not in the database."); - } - return r.get(); + return tryConnectionType(ipAddress).orElseThrow(() -> + new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database.")); } @Override public Optional tryConnectionType(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return getConnectionType(ipAddress); - } - - private Optional getConnectionType( - InetAddress ipAddress - ) throws IOException, GeoIp2Exception { - LookupResult result = this.get( + return getResponse( ipAddress, ConnectionTypeResponse.class, - DatabaseType.CONNECTION_TYPE - ); - ConnectionTypeResponse response = result.model(); - if (response == null) { - return Optional.empty(); - } - return Optional.of( - new ConnectionTypeResponse( - response, - result.ipAddress(), - result.network() - ) + DatabaseType.CONNECTION_TYPE, + "connectionType" ); } @@ -604,39 +486,15 @@ private Optional getConnectionType( @Override public DomainResponse domain(InetAddress ipAddress) throws IOException, GeoIp2Exception { - Optional r = getDomain(ipAddress); - if (r.isEmpty()) { - throw new AddressNotFoundException("The address " - + ipAddress.getHostAddress() + " is not in the database."); - } - return r.get(); + return tryDomain(ipAddress).orElseThrow(() -> + new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database.")); } @Override public Optional tryDomain(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return getDomain(ipAddress); - } - - private Optional getDomain( - InetAddress ipAddress - ) throws IOException, GeoIp2Exception { - LookupResult result = this.get( - ipAddress, - DomainResponse.class, - DatabaseType.DOMAIN - ); - DomainResponse response = result.model(); - if (response == null) { - return Optional.empty(); - } - return Optional.of( - new DomainResponse( - response, - result.ipAddress(), - result.network() - ) - ); + return getResponse(ipAddress, DomainResponse.class, DatabaseType.DOMAIN, "domain"); } /** @@ -650,40 +508,21 @@ private Optional getDomain( @Override public EnterpriseResponse enterprise(InetAddress ipAddress) throws IOException, GeoIp2Exception { - Optional r = getEnterprise(ipAddress); - if (r.isEmpty()) { - throw new AddressNotFoundException("The address " - + ipAddress.getHostAddress() + " is not in the database."); - } - return r.get(); + return tryEnterprise(ipAddress).orElseThrow(() -> + new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database.")); } @Override public Optional tryEnterprise(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return getEnterprise(ipAddress); - } - - private Optional getEnterprise( - InetAddress ipAddress - ) throws IOException, GeoIp2Exception { - LookupResult result = this.get( + var response = getResponse( ipAddress, EnterpriseResponse.class, - DatabaseType.ENTERPRISE - ); - EnterpriseResponse response = result.model(); - if (response == null) { - return Optional.empty(); - } - return Optional.of( - new EnterpriseResponse( - response, - result.ipAddress(), - result.network(), - locales - ) + DatabaseType.ENTERPRISE, + "enterprise" ); + return response.map(r -> new EnterpriseResponse(r, locales)); } /** @@ -697,45 +536,30 @@ private Optional getEnterprise( @Override public IspResponse isp(InetAddress ipAddress) throws IOException, GeoIp2Exception { - Optional r = getIsp(ipAddress); - if (r.isEmpty()) { - throw new AddressNotFoundException("The address " - + ipAddress.getHostAddress() + " is not in the database."); - } - return r.get(); + return tryIsp(ipAddress).orElseThrow(() -> + new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database.")); } @Override public Optional tryIsp(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return getIsp(ipAddress); + return getResponse(ipAddress, IspResponse.class, DatabaseType.ISP, "isp"); } - private Optional getIsp( - InetAddress ipAddress - ) throws IOException, GeoIp2Exception { - LookupResult result = this.get( - ipAddress, - IspResponse.class, - DatabaseType.ISP - ); - IspResponse response = result.model(); - if (response == null) { - return Optional.empty(); - } - return Optional.of( - new IspResponse( - response, - result.ipAddress(), - result.network() - ) - ); + /** + * @return the metadata for the open MaxMind DB file. + */ + public Metadata metadata() { + return this.reader.getMetadata(); } /** * @return the metadata for the open MaxMind DB file. + * @deprecated Use {@link #metadata()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) public Metadata getMetadata() { - return this.reader.getMetadata(); + return metadata(); } } diff --git a/src/main/java/com/maxmind/geoip2/InetAddressDeserializer.java b/src/main/java/com/maxmind/geoip2/InetAddressDeserializer.java new file mode 100644 index 00000000..8c61609b --- /dev/null +++ b/src/main/java/com/maxmind/geoip2/InetAddressDeserializer.java @@ -0,0 +1,34 @@ +package com.maxmind.geoip2; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * Deserializes a string to an InetAddress. + */ +public class InetAddressDeserializer extends StdDeserializer { + /** + * Constructs an instance of {@code InetAddressDeserializer}. + */ + public InetAddressDeserializer() { + super(InetAddress.class); + } + + @Override + public InetAddress deserialize(JsonParser p, DeserializationContext ctxt) + throws IOException { + var value = p.getValueAsString(); + if (value == null || value.isEmpty()) { + return null; + } + try { + return InetAddress.getByName(value); + } catch (UnknownHostException e) { + throw new IOException("Invalid IP address: " + value, e); + } + } +} diff --git a/src/main/java/com/maxmind/geoip2/InetAddressModule.java b/src/main/java/com/maxmind/geoip2/InetAddressModule.java new file mode 100644 index 00000000..6b989a4a --- /dev/null +++ b/src/main/java/com/maxmind/geoip2/InetAddressModule.java @@ -0,0 +1,18 @@ +package com.maxmind.geoip2; + +import com.fasterxml.jackson.databind.module.SimpleModule; +import java.net.InetAddress; + +/** + * Jackson module for InetAddress serialization and deserialization. + */ +public class InetAddressModule extends SimpleModule { + /** + * Constructs an instance of {@code InetAddressModule}. + */ + public InetAddressModule() { + super("InetAddressModule"); + addSerializer(InetAddress.class, new InetAddressSerializer()); + addDeserializer(InetAddress.class, new InetAddressDeserializer()); + } +} diff --git a/src/main/java/com/maxmind/geoip2/InetAddressSerializer.java b/src/main/java/com/maxmind/geoip2/InetAddressSerializer.java new file mode 100644 index 00000000..38319841 --- /dev/null +++ b/src/main/java/com/maxmind/geoip2/InetAddressSerializer.java @@ -0,0 +1,29 @@ +package com.maxmind.geoip2; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import java.io.IOException; +import java.net.InetAddress; + +/** + * Serializes InetAddress to its host address string representation. + */ +public class InetAddressSerializer extends StdSerializer { + /** + * Constructs an instance of {@code InetAddressSerializer}. + */ + public InetAddressSerializer() { + super(InetAddress.class); + } + + @Override + public void serialize(InetAddress value, JsonGenerator gen, SerializerProvider provider) + throws IOException { + if (value == null) { + gen.writeNull(); + } else { + gen.writeString(value.getHostAddress()); + } + } +} diff --git a/src/main/java/com/maxmind/geoip2/record/AbstractRecord.java b/src/main/java/com/maxmind/geoip2/JsonSerializable.java similarity index 61% rename from src/main/java/com/maxmind/geoip2/record/AbstractRecord.java rename to src/main/java/com/maxmind/geoip2/JsonSerializable.java index 631d795d..190553cd 100644 --- a/src/main/java/com/maxmind/geoip2/record/AbstractRecord.java +++ b/src/main/java/com/maxmind/geoip2/JsonSerializable.java @@ -1,23 +1,27 @@ -package com.maxmind.geoip2.record; +package com.maxmind.geoip2; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import java.io.IOException; /** - * Abstract class for GeoIP2. + * Interface for classes that can be serialized to JSON. + * Provides default implementation for toJson() method. */ -public abstract class AbstractRecord { +public interface JsonSerializable { /** * @return JSON representation of this object. The structure is the same as * the JSON provided by the GeoIP2 web service. * @throws IOException if there is an error serializing the object to JSON. */ - public String toJson() throws IOException { + default String toJson() throws IOException { JsonMapper mapper = JsonMapper.builder() .disable(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS) + .addModule(new JavaTimeModule()) + .addModule(new InetAddressModule()) .serializationInclusion(JsonInclude.Include.NON_NULL) .serializationInclusion(JsonInclude.Include.NON_EMPTY) .build(); @@ -25,14 +29,4 @@ public String toJson() throws IOException { return mapper.writeValueAsString(this); } - @Override - public String toString() { - // This exception should never happen. If it does happen, we did - // something wrong. - try { - return getClass().getName() + " [ " + toJson() + " ]"; - } catch (IOException e) { - throw new RuntimeException(e); - } - } } diff --git a/src/main/java/com/maxmind/geoip2/NamedRecord.java b/src/main/java/com/maxmind/geoip2/NamedRecord.java new file mode 100644 index 00000000..b2c30ebd --- /dev/null +++ b/src/main/java/com/maxmind/geoip2/NamedRecord.java @@ -0,0 +1,47 @@ +package com.maxmind.geoip2; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import java.util.Map; + +/** + * Interface for record classes that have localized names and GeoName IDs. + * Provides a default implementation for the name() method that returns the name + * in the first available locale. + */ +public interface NamedRecord extends JsonSerializable { + + /** + * @return The GeoName ID for this location. + */ + @JsonProperty("geoname_id") + Long geonameId(); + + /** + * @return A {@link Map} from locale codes to the name in that locale. + */ + @JsonProperty("names") + Map names(); + + /** + * @return The list of locales to use for name lookups. + */ + @JsonIgnore + List locales(); + + /** + * @return The name based on the locales list. Returns the name in the first + * locale for which a name is available. If no name is available in any of the + * specified locales, returns null. + */ + @JsonIgnore + default String name() { + for (var lang : locales()) { + if (names().containsKey(lang)) { + return names().get(lang); + } + } + return null; + } +} diff --git a/src/main/java/com/maxmind/geoip2/NetworkDeserializer.java b/src/main/java/com/maxmind/geoip2/NetworkDeserializer.java index 7932b6f2..670ddc52 100644 --- a/src/main/java/com/maxmind/geoip2/NetworkDeserializer.java +++ b/src/main/java/com/maxmind/geoip2/NetworkDeserializer.java @@ -33,7 +33,7 @@ public NetworkDeserializer(Class vc) { public Network deserialize(JsonParser jsonparser, DeserializationContext context) throws IOException { - final String cidr = jsonparser.getValueAsString(); + final var cidr = jsonparser.getValueAsString(); if (cidr == null || cidr.isBlank()) { return null; } @@ -41,13 +41,13 @@ public Network deserialize(JsonParser jsonparser, DeserializationContext context } private static Network parseCidr(String cidr) throws IOException { - final String[] parts = cidr.split("/", 2); + final var parts = cidr.split("/", 2); if (parts.length != 2) { throw new IllegalArgumentException("Invalid CIDR format: " + cidr); } - final String addrPart = parts[0]; - final String prefixPart = parts[1]; + final var addrPart = parts[0]; + final var prefixPart = parts[1]; final InetAddress address; try { @@ -56,15 +56,9 @@ private static Network parseCidr(String cidr) throws IOException { throw new IOException("Unknown host in CIDR: " + cidr, e); } - final int prefixLength; - try { - prefixLength = Integer.parseInt(prefixPart); - } catch (NumberFormatException e) { - throw new IllegalArgumentException( - "Invalid prefix length in CIDR: " + cidr, e); - } + final var prefixLength = parsePrefixLength(prefixPart, cidr); - final int maxPrefix = (address.getAddress().length == 4) ? 32 : 128; + final var maxPrefix = (address.getAddress().length == 4) ? 32 : 128; if (prefixLength < 0 || prefixLength > maxPrefix) { throw new IllegalArgumentException( "Prefix length out of range (0-" + maxPrefix + ") for CIDR: " + cidr); @@ -72,4 +66,13 @@ private static Network parseCidr(String cidr) throws IOException { return new Network(address, prefixLength); } + + private static int parsePrefixLength(String prefixPart, String cidr) { + try { + return Integer.parseInt(prefixPart); + } catch (NumberFormatException e) { + throw new IllegalArgumentException( + "Invalid prefix length in CIDR: " + cidr, e); + } + } } diff --git a/src/main/java/com/maxmind/geoip2/WebServiceClient.java b/src/main/java/com/maxmind/geoip2/WebServiceClient.java index 2e653201..c48169a9 100644 --- a/src/main/java/com/maxmind/geoip2/WebServiceClient.java +++ b/src/main/java/com/maxmind/geoip2/WebServiceClient.java @@ -356,9 +356,9 @@ public InsightsResponse insights(InetAddress ipAddress) throws IOException, private T responseFor(String path, InetAddress ipAddress, Class cls) throws IOException, GeoIp2Exception { - URI uri = createUri(path, ipAddress); + var uri = createUri(path, ipAddress); - HttpRequest request = HttpRequest.newBuilder() + var request = HttpRequest.newBuilder() .uri(uri) .timeout(this.requestTimeout) .header("Accept", "application/json") @@ -366,24 +366,23 @@ private T responseFor(String path, InetAddress ipAddress, Class cls) .header("User-Agent", this.userAgent) .GET() .build(); - HttpResponse response = null; try { - response = this.httpClient + var response = this.httpClient .send(request, HttpResponse.BodyHandlers.ofInputStream()); - return handleResponse(response, cls); - } catch (InterruptedException e) { - throw new GeoIp2Exception("Interrupted sending request", e); - } finally { - if (response != null) { + try { + return handleResponse(response, cls); + } finally { response.body().close(); } + } catch (InterruptedException e) { + throw new GeoIp2Exception("Interrupted sending request", e); } } private T handleResponse(HttpResponse response, Class cls) throws GeoIp2Exception, IOException { - int status = response.statusCode(); - URI uri = response.uri(); + var status = response.statusCode(); + var uri = response.uri(); if (status >= 400 && status < 500) { this.handle4xxStatus(response); @@ -397,7 +396,7 @@ private T handleResponse(HttpResponse response, Class cls) + status + ") for " + uri, status, uri); } - InjectableValues inject = new InjectableValues.Std() + var inject = new InjectableValues.Std() .addValue("locales", locales); try { @@ -410,20 +409,17 @@ private T handleResponse(HttpResponse response, Class cls) private void handle4xxStatus(HttpResponse response) throws GeoIp2Exception, IOException { - int status = response.statusCode(); - URI uri = response.uri(); - - String body; - try (InputStream bodyStream = response.body()) { - body = new String(bodyStream.readAllBytes(), StandardCharsets.UTF_8); - if (body.equals("")) { - throw new HttpException("Received a " + status + " error for " - + uri + " with no body", status, uri); - } + var status = response.statusCode(); + var uri = response.uri(); + + final var body = readBody(response); + if (body.isEmpty()) { + throw new HttpException("Received a " + status + " error for " + + uri + " with no body", status, uri); } try { - Map content = mapper.readValue(body, + var content = mapper.readValue(body, new TypeReference>() { }); handleErrorWithJsonBody(content, body, status, uri); @@ -439,8 +435,8 @@ private void handle4xxStatus(HttpResponse response) private static void handleErrorWithJsonBody(Map content, String body, int status, URI uri) throws GeoIp2Exception, HttpException { - String error = content.get("error"); - String code = content.get("code"); + var error = content.get("error"); + var code = content.get("code"); if (error == null || code == null) { throw new HttpException( @@ -449,29 +445,23 @@ private static void handleErrorWithJsonBody(Map content, } switch (code) { - case "IP_ADDRESS_NOT_FOUND": - case "IP_ADDRESS_RESERVED": + case "IP_ADDRESS_NOT_FOUND", "IP_ADDRESS_RESERVED" -> throw new AddressNotFoundException(error); - case "ACCOUNT_ID_REQUIRED": - case "ACCOUNT_ID_UNKNOWN": - case "AUTHORIZATION_INVALID": - case "LICENSE_KEY_REQUIRED": - case "USER_ID_REQUIRED": - case "USER_ID_UNKNOWN": + case "ACCOUNT_ID_REQUIRED", "ACCOUNT_ID_UNKNOWN", "AUTHORIZATION_INVALID", + "LICENSE_KEY_REQUIRED", "USER_ID_REQUIRED", "USER_ID_UNKNOWN" -> throw new AuthenticationException(error); - case "INSUFFICIENT_FUNDS": - case "OUT_OF_QUERIES": + case "INSUFFICIENT_FUNDS", "OUT_OF_QUERIES" -> throw new OutOfQueriesException(error); - case "PERMISSION_REQUIRED": + case "PERMISSION_REQUIRED" -> throw new PermissionRequiredException(error); - default: + default -> // These should be fairly rare throw new InvalidRequestException(error, code, uri); } } private URI createUri(String service, InetAddress ipAddress) throws GeoIp2Exception { - String path = "/geoip/v2.1/" + service + "/" + var path = "/geoip/v2.1/" + service + "/" + (ipAddress == null ? "me" : ipAddress.getHostAddress()); try { return new URI( @@ -489,7 +479,7 @@ private URI createUri(String service, InetAddress ipAddress) throws GeoIp2Except } private void exhaustBody(HttpResponse response) throws HttpException { - try (InputStream body = response.body()) { + try (var body = response.body()) { // Make sure we read the stream until the end so that // the connection can be reused. while (body.read() != -1) { @@ -500,6 +490,11 @@ private void exhaustBody(HttpResponse response) throws HttpExceptio } } + private static String readBody(HttpResponse response) throws IOException { + try (var bodyStream = response.body()) { + return new String(bodyStream.readAllBytes(), StandardCharsets.UTF_8); + } + } @Override public String toString() { diff --git a/src/main/java/com/maxmind/geoip2/exception/GeoIp2Exception.java b/src/main/java/com/maxmind/geoip2/exception/GeoIp2Exception.java index 967cd034..24afd18d 100644 --- a/src/main/java/com/maxmind/geoip2/exception/GeoIp2Exception.java +++ b/src/main/java/com/maxmind/geoip2/exception/GeoIp2Exception.java @@ -4,7 +4,12 @@ * This class represents a generic GeoIP2 error. All other exceptions thrown by * the GeoIP2 API subclass this exception */ -public class GeoIp2Exception extends Exception { +public sealed class GeoIp2Exception extends Exception + permits AddressNotFoundException, + AuthenticationException, + InvalidRequestException, + OutOfQueriesException, + PermissionRequiredException { /** diff --git a/src/main/java/com/maxmind/geoip2/exception/HttpException.java b/src/main/java/com/maxmind/geoip2/exception/HttpException.java index a73d8f9d..7cf497b6 100644 --- a/src/main/java/com/maxmind/geoip2/exception/HttpException.java +++ b/src/main/java/com/maxmind/geoip2/exception/HttpException.java @@ -39,16 +39,34 @@ public HttpException(String message, int httpStatus, URI uri, /** * @return the HTTP status of the query that caused the exception. */ - public int getHttpStatus() { + public int httpStatus() { return this.httpStatus; } + /** + * @return the HTTP status of the query that caused the exception. + * @deprecated Use {@link #httpStatus()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public int getHttpStatus() { + return httpStatus(); + } + /** * @return the URI queried. */ - public URI getUri() { + public URI uri() { return this.uri; } + /** + * @return the URI queried. + * @deprecated Use {@link #uri()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public URI getUri() { + return uri(); + } + } diff --git a/src/main/java/com/maxmind/geoip2/exception/InvalidRequestException.java b/src/main/java/com/maxmind/geoip2/exception/InvalidRequestException.java index 58c845d7..1acd388e 100644 --- a/src/main/java/com/maxmind/geoip2/exception/InvalidRequestException.java +++ b/src/main/java/com/maxmind/geoip2/exception/InvalidRequestException.java @@ -39,15 +39,33 @@ public InvalidRequestException(String message, String code, int httpStatus, /** * @return The error code returned by the MaxMind web service. */ - public String getCode() { + public String code() { return this.code; } + /** + * @return The error code returned by the MaxMind web service. + * @deprecated Use {@link #code()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public String getCode() { + return code(); + } + /** * @return the URI queried. */ - public URI getUri() { + public URI uri() { return this.uri; } + /** + * @return the URI queried. + * @deprecated Use {@link #uri()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public URI getUri() { + return uri(); + } + } diff --git a/src/main/java/com/maxmind/geoip2/model/AbstractCityResponse.java b/src/main/java/com/maxmind/geoip2/model/AbstractCityResponse.java deleted file mode 100644 index 6cc4bec2..00000000 --- a/src/main/java/com/maxmind/geoip2/model/AbstractCityResponse.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.maxmind.geoip2.model; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.maxmind.db.Network; -import com.maxmind.geoip2.record.City; -import com.maxmind.geoip2.record.Continent; -import com.maxmind.geoip2.record.Country; -import com.maxmind.geoip2.record.Location; -import com.maxmind.geoip2.record.MaxMind; -import com.maxmind.geoip2.record.Postal; -import com.maxmind.geoip2.record.RepresentedCountry; -import com.maxmind.geoip2.record.Subdivision; -import com.maxmind.geoip2.record.Traits; -import java.util.ArrayList; -import java.util.List; - -/** - * Abstract class for models that contain City data. - */ -public abstract class AbstractCityResponse extends AbstractCountryResponse { - - private final City city; - private final Location location; - private final Postal postal; - private final List subdivisions; - - AbstractCityResponse( - City city, - Continent continent, - Country country, - Location location, - MaxMind maxmind, - Postal postal, - Country registeredCountry, - RepresentedCountry representedCountry, - List subdivisions, - Traits traits - ) { - super(continent, country, maxmind, registeredCountry, representedCountry, traits); - this.city = city != null ? city : new City(); - this.location = location != null ? location : new Location(); - this.postal = postal != null ? postal : new Postal(); - this.subdivisions = subdivisions != null ? subdivisions : new ArrayList<>(); - } - - AbstractCityResponse( - AbstractCityResponse response, - String ipAddress, - Network network, - List locales - ) { - super(response, ipAddress, network, locales); - // The response fields will be non-null because of the above - // constructor used during deserializing. - this.city = new City(response.getCity(), locales); - this.location = response.getLocation(); - this.postal = response.getPostal(); - this.subdivisions = mapSubdivisions(response.getSubdivisions(), locales); - } - - private static ArrayList mapSubdivisions( - List subdivisions, - List locales - ) { - ArrayList subdivisions2 = new ArrayList<>(subdivisions.size()); - for (Subdivision subdivision : subdivisions) { - subdivisions2.add(new Subdivision(subdivision, locales)); - } - return subdivisions2; - } - - /** - * @return City record for the requested IP address. - */ - public City getCity() { - return this.city; - } - - /** - * @return Location record for the requested IP address. - */ - public Location getLocation() { - return this.location; - } - - /** - * @return the postal - */ - public Postal getPostal() { - return this.postal; - } - - /** - * @return An {@link List} of {@link Subdivision} objects representing the - * country subdivisions for the requested IP address. The number and - * type of subdivisions varies by country, but a subdivision is - * typically a state, province, county, etc. Subdivisions are - * ordered from most general (largest) to most specific (smallest). - * If the response did not contain any subdivisions, this method - * returns an empty array. - */ - public List getSubdivisions() { - return new ArrayList<>(this.subdivisions); - } - - /** - * @return An object representing the most specific subdivision returned. If - * the response did not contain any subdivisions, this method - * returns an empty {@link Subdivision} object. - */ - @JsonIgnore - public Subdivision getMostSpecificSubdivision() { - if (this.subdivisions.isEmpty()) { - return new Subdivision(); - } - return this.subdivisions.get(this.subdivisions.size() - 1); - } - - /** - * @return An object representing the least specific subdivision returned. If - * the response did not contain any subdivisions, this method - * returns an empty {@link Subdivision} object. - */ - @JsonIgnore - public Subdivision getLeastSpecificSubdivision() { - if (this.subdivisions.isEmpty()) { - return new Subdivision(); - } - return this.subdivisions.get(0); - } -} diff --git a/src/main/java/com/maxmind/geoip2/model/AbstractCountryResponse.java b/src/main/java/com/maxmind/geoip2/model/AbstractCountryResponse.java deleted file mode 100644 index 615e1765..00000000 --- a/src/main/java/com/maxmind/geoip2/model/AbstractCountryResponse.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.maxmind.geoip2.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.maxmind.db.Network; -import com.maxmind.geoip2.record.Continent; -import com.maxmind.geoip2.record.Country; -import com.maxmind.geoip2.record.MaxMind; -import com.maxmind.geoip2.record.RepresentedCountry; -import com.maxmind.geoip2.record.Traits; -import java.util.List; - -/** -* Abstract class for models that contain Country data. - */ -public abstract class AbstractCountryResponse extends AbstractResponse { - - private final Continent continent; - private final Country country; - private final Country registeredCountry; - private final MaxMind maxmind; - private final RepresentedCountry representedCountry; - private final Traits traits; - - AbstractCountryResponse( - Continent continent, - Country country, - MaxMind maxmind, - Country registeredCountry, - RepresentedCountry representedCountry, - Traits traits - ) { - this.continent = continent != null ? continent : new Continent(); - this.country = country != null ? country : new Country(); - this.registeredCountry = registeredCountry != null ? registeredCountry : new Country(); - this.maxmind = maxmind != null ? maxmind : new MaxMind(); - this.representedCountry = - representedCountry != null ? representedCountry : new RepresentedCountry(); - this.traits = traits != null ? traits : new Traits(); - } - - AbstractCountryResponse( - AbstractCountryResponse response, - String ipAddress, - Network network, - List locales - ) { - // The response fields will be non-null because of the above - // constructor used during deserializing. - this.continent = new Continent(response.getContinent(), locales); - this.country = new Country(response.getCountry(), locales); - this.maxmind = response.getMaxMind(); - this.registeredCountry = new Country(response.getRegisteredCountry(), locales); - this.representedCountry = new RepresentedCountry(response.getRepresentedCountry(), locales); - this.traits = new Traits(response.getTraits(), ipAddress, network); - } - - /** - * @return MaxMind record containing data related to your account. - */ - @JsonProperty("maxmind") - public MaxMind getMaxMind() { - return this.maxmind; - } - - /** - * @return Registered country record for the requested IP address. This - * record represents the country where the ISP has registered a - * given IP block and may differ from the user's country. - */ - @JsonProperty("registered_country") - public Country getRegisteredCountry() { - return this.registeredCountry; - } - - /** - * @return Continent record for the requested IP address. - */ - public Continent getContinent() { - return this.continent; - } - - /** - * @return Country record for the requested IP address. This object - * represents the country where MaxMind believes the end user is - * located. - */ - public Country getCountry() { - return this.country; - } - - /** - * @return Represented country record for the requested IP address. The - * represented country is used for things like military bases. It is - * only present when the represented country differs from the - * country. - */ - @JsonProperty("represented_country") - public RepresentedCountry getRepresentedCountry() { - return this.representedCountry; - } - - /** - * @return Record for the traits of the requested IP address. - */ - public Traits getTraits() { - return this.traits; - } -} diff --git a/src/main/java/com/maxmind/geoip2/model/AbstractResponse.java b/src/main/java/com/maxmind/geoip2/model/AbstractResponse.java deleted file mode 100644 index 6c742f1b..00000000 --- a/src/main/java/com/maxmind/geoip2/model/AbstractResponse.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.maxmind.geoip2.model; - -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.databind.json.JsonMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import java.io.IOException; - -/** - * Abstract class for GeoIP2 models. - */ -public abstract class AbstractResponse { - - /** - * @return JSON representation of this object. The structure is the same as - * the JSON provided by the GeoIP2 web service. - * @throws IOException if there is an error serializing the object to JSON. - */ - public String toJson() throws IOException { - JsonMapper mapper = JsonMapper.builder() - .disable(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS) - .addModule(new JavaTimeModule()) - .serializationInclusion(Include.NON_NULL) - .serializationInclusion(Include.NON_EMPTY) - .build(); - - return mapper.writeValueAsString(this); - } - - @Override - public String toString() { - // This exception should never happen. If it does happen, we did - // something wrong. - try { - return getClass().getName() + " [ " + toJson() + " ]"; - } catch (IOException e) { - throw new RuntimeException(e); - } - } -} diff --git a/src/main/java/com/maxmind/geoip2/model/AnonymousIpResponse.java b/src/main/java/com/maxmind/geoip2/model/AnonymousIpResponse.java index 923023b9..c8a22226 100644 --- a/src/main/java/com/maxmind/geoip2/model/AnonymousIpResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/AnonymousIpResponse.java @@ -1,102 +1,89 @@ package com.maxmind.geoip2.model; -import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.maxmind.db.MaxMindDbConstructor; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.maxmind.db.MaxMindDbIpAddress; +import com.maxmind.db.MaxMindDbNetwork; import com.maxmind.db.MaxMindDbParameter; import com.maxmind.db.Network; +import com.maxmind.geoip2.JsonSerializable; import com.maxmind.geoip2.NetworkDeserializer; +import java.net.InetAddress; /** * This class provides the GeoIP2 Anonymous IP model. + * + * @param ipAddress The IP address that the data in the model is for. + * @param isAnonymous Whether the IP address belongs to any sort of anonymous network. + * @param isAnonymousVpn Whether the IP address is registered to an anonymous VPN provider. If a + * VPN provider does not register subnets under names associated with them, + * we will likely only flag their IP ranges using isHostingProvider. + * @param isHostingProvider Whether the IP address belongs to a hosting or VPN provider (see + * description of isAnonymousVpn). + * @param isPublicProxy Whether the IP address belongs to a public proxy. + * @param isResidentialProxy Whether the IP address is on a suspected anonymizing network and + * belongs to a residential ISP. + * @param isTorExitNode Whether the IP address is a Tor exit node. + * @param network The network associated with the record. In particular, this is the largest + * network where all the fields besides IP address have the same value. */ -public class AnonymousIpResponse extends IpBaseResponse { +public record AnonymousIpResponse( + @JsonProperty("ip_address") + @MaxMindDbIpAddress + InetAddress ipAddress, - /** - * Constructs an instance of {@code AnonymousIpResponse} with the specified values. - * - * @param ipAddress the IP address being checked - * @param isAnonymous whether the IP address belongs to any sort of anonymous network - * @param isAnonymousVpn whether the IP address belongs to an anonymous VPN system - * @param isHostingProvider whether the IP address belongs to a hosting provider - * @param isPublicProxy whether the IP address belongs to a public proxy system - * @param isResidentialProxy whether the IP address belongs to a residential proxy system - * @param isTorExitNode whether the IP address is a Tor exit node - * @param network the network associated with the record - */ - public AnonymousIpResponse( - @JsonProperty("ip_address") String ipAddress, - @JsonProperty("is_anonymous") boolean isAnonymous, - @JsonProperty("is_anonymous_vpn") boolean isAnonymousVpn, - @JsonProperty("is_hosting_provider") boolean isHostingProvider, - @JsonProperty("is_public_proxy") boolean isPublicProxy, - @JsonProperty("is_residential_proxy") boolean isResidentialProxy, - @JsonProperty("is_tor_exit_node") boolean isTorExitNode, - @JsonProperty("network") - @JsonDeserialize(using = NetworkDeserializer.class) Network network - ) { - super(ipAddress, isAnonymous, isAnonymousVpn, isHostingProvider, isPublicProxy, - isResidentialProxy, isTorExitNode, network); - } + @JsonProperty("is_anonymous") + @MaxMindDbParameter(name = "is_anonymous", useDefault = true) + boolean isAnonymous, + + @JsonProperty("is_anonymous_vpn") + @MaxMindDbParameter(name = "is_anonymous_vpn", useDefault = true) + boolean isAnonymousVpn, + + @JsonProperty("is_hosting_provider") + @MaxMindDbParameter(name = "is_hosting_provider", useDefault = true) + boolean isHostingProvider, + + @JsonProperty("is_public_proxy") + @MaxMindDbParameter(name = "is_public_proxy", useDefault = true) + boolean isPublicProxy, + + @JsonProperty("is_residential_proxy") + @MaxMindDbParameter(name = "is_residential_proxy", useDefault = true) + boolean isResidentialProxy, + + @JsonProperty("is_tor_exit_node") + @MaxMindDbParameter(name = "is_tor_exit_node", useDefault = true) + boolean isTorExitNode, + + @JsonProperty("network") + @JsonDeserialize(using = NetworkDeserializer.class) + @MaxMindDbNetwork + Network network +) implements JsonSerializable { /** - * Constructs an instance of {@code AnonymousIpResponse} with the specified values. - * - * @param ipAddress the IP address being checked - * @param isAnonymous whether the IP address belongs to any sort of anonymous network - * @param isAnonymousVpn whether the IP address belongs to an anonymous VPN system - * @param isHostingProvider whether the IP address belongs to a hosting provider - * @param isPublicProxy whether the IP address belongs to a public proxy system - * @param isResidentialProxy whether the IP address belongs to a residential proxy system - * @param isTorExitNode whether the IP address is a Tor exit node - * @param network the network associated with the record + * @return The IP address that the data in the model is for. + * @deprecated Use {@link #ipAddress()} instead. This method will be removed in 6.0.0. */ - @MaxMindDbConstructor - public AnonymousIpResponse( - @MaxMindDbParameter(name = "ip_address") String ipAddress, - @MaxMindDbParameter(name = "is_anonymous") Boolean isAnonymous, - @MaxMindDbParameter(name = "is_anonymous_vpn") Boolean isAnonymousVpn, - @MaxMindDbParameter(name = "is_hosting_provider") Boolean isHostingProvider, - @MaxMindDbParameter(name = "is_public_proxy") Boolean isPublicProxy, - @MaxMindDbParameter(name = "is_residential_proxy") Boolean isResidentialProxy, - @MaxMindDbParameter(name = "is_tor_exit_node") Boolean isTorExitNode, - @MaxMindDbParameter(name = "network") Network network - ) { - this( - ipAddress, - isAnonymous != null ? isAnonymous : false, - isAnonymousVpn != null ? isAnonymousVpn : false, - isHostingProvider != null ? isHostingProvider : false, - isPublicProxy != null ? isPublicProxy : false, - isResidentialProxy != null ? isResidentialProxy : false, - isTorExitNode != null ? isTorExitNode : false, - network - ); + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("ip_address") + public String getIpAddress() { + return ipAddress().getHostAddress(); } /** - * Constructs an instance of {@code AnonymousIpResponse} from the values in the passed - * response and the specified IP address and network. - * - * @param response the response to copy - * @param ipAddress the IP address being checked - * @param network the network associated with the record + * @return The network associated with the record. In particular, this is + * the largest network where all the fields besides IP address have the + * same value. + * @deprecated Use {@link #network()} instead. This method will be removed in 6.0.0. */ - public AnonymousIpResponse( - AnonymousIpResponse response, - String ipAddress, - Network network - ) { - this( - ipAddress, - response.isAnonymous(), - response.isAnonymousVpn(), - response.isHostingProvider(), - response.isPublicProxy(), - response.isResidentialProxy(), - response.isTorExitNode(), - network - ); + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty + @JsonSerialize(using = ToStringSerializer.class) + public Network getNetwork() { + return network(); } } diff --git a/src/main/java/com/maxmind/geoip2/model/AnonymousPlusResponse.java b/src/main/java/com/maxmind/geoip2/model/AnonymousPlusResponse.java index 169d1e2a..22ac498b 100644 --- a/src/main/java/com/maxmind/geoip2/model/AnonymousPlusResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/AnonymousPlusResponse.java @@ -1,63 +1,93 @@ package com.maxmind.geoip2.model; -import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.maxmind.db.MaxMindDbConstructor; +import com.maxmind.db.MaxMindDbIpAddress; +import com.maxmind.db.MaxMindDbNetwork; import com.maxmind.db.MaxMindDbParameter; import com.maxmind.db.Network; +import com.maxmind.geoip2.JsonSerializable; import com.maxmind.geoip2.NetworkDeserializer; +import java.net.InetAddress; import java.time.LocalDate; /** * This class provides the GeoIP Anonymous Plus model. + * + * @param ipAddress The IP address that the data in the model is for. + * @param isAnonymous Whether the IP address belongs to any sort of anonymous network. + * @param isAnonymousVpn Whether the IP address is registered to an anonymous VPN provider. If a + * VPN provider does not register subnets under names associated with them, + * we will likely only flag their IP ranges using isHostingProvider. + * @param isHostingProvider Whether the IP address belongs to a hosting or VPN provider (see + * description of isAnonymousVpn). + * @param isPublicProxy Whether the IP address belongs to a public proxy. + * @param isResidentialProxy Whether the IP address is on a suspected anonymizing network and + * belongs to a residential ISP. + * @param isTorExitNode Whether the IP address is a Tor exit node. + * @param network The network associated with the record. In particular, this is the largest + * network where all the fields besides IP address have the same value. + * @param anonymizerConfidence A score ranging from 1 to 99 that is our percent confidence that + * the network is currently part of an actively used VPN service. + * @param networkLastSeen The last day that the network was sighted in our analysis of anonymized + * networks. + * @param providerName The name of the VPN provider (e.g., NordVPN, SurfShark, etc.) associated + * with the network. */ -public class AnonymousPlusResponse extends AnonymousIpResponse { - private final Integer anonymizerConfidence; - private final LocalDate networkLastSeen; - private final String providerName; +public record AnonymousPlusResponse( + @JsonProperty("ip_address") + @MaxMindDbIpAddress + InetAddress ipAddress, - /** - * Constructs an instance of {@code AnonymousPlusResponse} with the specified values. - * - * @param anonymizerConfidence confidence that the network is a VPN. - * @param ipAddress the IP address being checked - * @param isAnonymous whether the IP address belongs to any sort of anonymous network - * @param isAnonymousVpn whether the IP address belongs to an anonymous VPN system - * @param isHostingProvider whether the IP address belongs to a hosting provider - * @param isPublicProxy whether the IP address belongs to a public proxy system - * @param isResidentialProxy whether the IP address belongs to a residential proxy system - * @param isTorExitNode whether the IP address is a Tor exit node - * @param network the network associated with the record - * @param networkLastSeen the last sighting of the network. - * @param providerName the name of the VPN provider. - */ - public AnonymousPlusResponse( - @JsonProperty("anonymizer_confidence") Integer anonymizerConfidence, - @JsonProperty("ip_address") String ipAddress, - @JsonProperty("is_anonymous") Boolean isAnonymous, - @JsonProperty("is_anonymous_vpn") Boolean isAnonymousVpn, - @JsonProperty("is_hosting_provider") Boolean isHostingProvider, - @JsonProperty("is_public_proxy") Boolean isPublicProxy, - @JsonProperty("is_residential_proxy") Boolean isResidentialProxy, - @JsonProperty("is_tor_exit_node") Boolean isTorExitNode, - @JsonDeserialize(using = NetworkDeserializer.class) - @JsonProperty("network") Network network, - @JsonProperty("network_last_seen") LocalDate networkLastSeen, - @JsonProperty("provider_name") String providerName - ) { - super(ipAddress, isAnonymous, isAnonymousVpn, isHostingProvider, isPublicProxy, - isResidentialProxy, isTorExitNode, network); + @JsonProperty("is_anonymous") + @MaxMindDbParameter(name = "is_anonymous", useDefault = true) + boolean isAnonymous, - this.anonymizerConfidence = anonymizerConfidence; - this.networkLastSeen = networkLastSeen; - this.providerName = providerName; - } + @JsonProperty("is_anonymous_vpn") + @MaxMindDbParameter(name = "is_anonymous_vpn", useDefault = true) + boolean isAnonymousVpn, + + @JsonProperty("is_hosting_provider") + @MaxMindDbParameter(name = "is_hosting_provider", useDefault = true) + boolean isHostingProvider, + + @JsonProperty("is_public_proxy") + @MaxMindDbParameter(name = "is_public_proxy", useDefault = true) + boolean isPublicProxy, + + @JsonProperty("is_residential_proxy") + @MaxMindDbParameter(name = "is_residential_proxy", useDefault = true) + boolean isResidentialProxy, + + @JsonProperty("is_tor_exit_node") + @MaxMindDbParameter(name = "is_tor_exit_node", useDefault = true) + boolean isTorExitNode, + + @JsonProperty("network") + @JsonDeserialize(using = NetworkDeserializer.class) + @MaxMindDbNetwork + Network network, + + @JsonProperty("anonymizer_confidence") + @MaxMindDbParameter(name = "anonymizer_confidence") + Integer anonymizerConfidence, + + @JsonProperty("network_last_seen") + @MaxMindDbParameter(name = "network_last_seen") + LocalDate networkLastSeen, + + @JsonProperty("provider_name") + @MaxMindDbParameter(name = "provider_name") + String providerName +) implements JsonSerializable { /** - * Constructs an instance of {@code AnonymousPlusResponse} with the specified values. + * Constructs an instance of {@code AnonymousPlusResponse} with date parsing + * from MaxMind database. * - * @param anonymizerConfidence confidence that the network is a VPN. * @param ipAddress the IP address being checked * @param isAnonymous whether the IP address belongs to any sort of anonymous network * @param isAnonymousVpn whether the IP address belongs to an anonymous VPN system @@ -66,80 +96,98 @@ public AnonymousPlusResponse( * @param isResidentialProxy whether the IP address belongs to a residential proxy system * @param isTorExitNode whether the IP address is a Tor exit node * @param network the network associated with the record + * @param anonymizerConfidence confidence that the network is a VPN. * @param networkLastSeen the last sighting of the network. * @param providerName the name of the VPN provider. */ @MaxMindDbConstructor public AnonymousPlusResponse( + @MaxMindDbIpAddress InetAddress ipAddress, + @MaxMindDbParameter(name = "is_anonymous", useDefault = true) + boolean isAnonymous, + @MaxMindDbParameter(name = "is_anonymous_vpn", useDefault = true) + boolean isAnonymousVpn, + @MaxMindDbParameter(name = "is_hosting_provider", useDefault = true) + boolean isHostingProvider, + @MaxMindDbParameter(name = "is_public_proxy", useDefault = true) + boolean isPublicProxy, + @MaxMindDbParameter(name = "is_residential_proxy", useDefault = true) + boolean isResidentialProxy, + @MaxMindDbParameter(name = "is_tor_exit_node", useDefault = true) + boolean isTorExitNode, + @MaxMindDbNetwork Network network, @MaxMindDbParameter(name = "anonymizer_confidence") Integer anonymizerConfidence, - @MaxMindDbParameter(name = "ip_address") String ipAddress, - @MaxMindDbParameter(name = "is_anonymous") Boolean isAnonymous, - @MaxMindDbParameter(name = "is_anonymous_vpn") Boolean isAnonymousVpn, - @MaxMindDbParameter(name = "is_hosting_provider") Boolean isHostingProvider, - @MaxMindDbParameter(name = "is_public_proxy") Boolean isPublicProxy, - @MaxMindDbParameter(name = "is_residential_proxy") Boolean isResidentialProxy, - @MaxMindDbParameter(name = "is_tor_exit_node") Boolean isTorExitNode, - @MaxMindDbParameter(name = "network") Network network, @MaxMindDbParameter(name = "network_last_seen") String networkLastSeen, @MaxMindDbParameter(name = "provider_name") String providerName ) { - this(anonymizerConfidence, ipAddress, isAnonymous, isAnonymousVpn, - isHostingProvider, isPublicProxy, isResidentialProxy, isTorExitNode, network, + this( + ipAddress, + isAnonymous, + isAnonymousVpn, + isHostingProvider, + isPublicProxy, + isResidentialProxy, + isTorExitNode, + network, + anonymizerConfidence, networkLastSeen != null ? LocalDate.parse(networkLastSeen) : null, - providerName); + providerName + ); } /** - * Constructs an instance of {@code AnonymousPlusResponse} from the values in the - * response and the specified IP address and network. - * - * @param response the response to copy - * @param ipAddress the IP address being checked - * @param network the network associated with the record + * @return The IP address that the data in the model is for. + * @deprecated Use {@link #ipAddress()} instead. This method will be removed in 6.0.0. */ - public AnonymousPlusResponse( - AnonymousPlusResponse response, - String ipAddress, - Network network - ) { - this( - response.getAnonymizerConfidence(), - ipAddress, - response.isAnonymous(), - response.isAnonymousVpn(), - response.isHostingProvider(), - response.isPublicProxy(), - response.isResidentialProxy(), - response.isTorExitNode(), - network, - response.getNetworkLastSeen(), - response.getProviderName() - ); + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("ip_address") + public String getIpAddress() { + return ipAddress().getHostAddress(); + } + + /** + * @return The network associated with the record. In particular, this is + * the largest network where all the fields besides IP address have the + * same value. + * @deprecated Use {@link #network()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty + @JsonSerialize(using = ToStringSerializer.class) + public Network getNetwork() { + return network(); } /** * @return A score ranging from 1 to 99 that is our percent confidence that the network is * currently part of an actively used VPN service. + * @deprecated Use {@link #anonymizerConfidence()} instead. This method will be removed + * in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty public Integer getAnonymizerConfidence() { - return anonymizerConfidence; + return anonymizerConfidence(); } /** * @return The last day that the network was sighted in our analysis of anonymized networks. + * @deprecated Use {@link #networkLastSeen()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty public LocalDate getNetworkLastSeen() { - return networkLastSeen; + return networkLastSeen(); } /** * @return The name of the VPN provider (e.g., NordVPN, SurfShark, etc.) associated with the * network. + * @deprecated Use {@link #providerName()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty public String getProviderName() { - return providerName; + return providerName(); } } diff --git a/src/main/java/com/maxmind/geoip2/model/AsnResponse.java b/src/main/java/com/maxmind/geoip2/model/AsnResponse.java index a33717d2..0dea5f03 100644 --- a/src/main/java/com/maxmind/geoip2/model/AsnResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/AsnResponse.java @@ -1,107 +1,89 @@ package com.maxmind.geoip2.model; -import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; -import com.maxmind.db.MaxMindDbConstructor; +import com.maxmind.db.MaxMindDbIpAddress; +import com.maxmind.db.MaxMindDbNetwork; import com.maxmind.db.MaxMindDbParameter; import com.maxmind.db.Network; +import com.maxmind.geoip2.JsonSerializable; import com.maxmind.geoip2.NetworkDeserializer; +import java.net.InetAddress; /** * This class provides the GeoLite2 ASN model. + * + * @param autonomousSystemNumber The autonomous system number associated with the IP address. + * @param autonomousSystemOrganization The organization associated with the registered autonomous + * system number for the IP address. + * @param ipAddress The IP address that the data in the model is for. + * @param network The network associated with the record. In particular, this is the largest + * network where all the fields besides IP address have the same value. */ -public class AsnResponse extends AbstractResponse { +public record AsnResponse( + @JsonProperty("autonomous_system_number") + @MaxMindDbParameter(name = "autonomous_system_number") + Long autonomousSystemNumber, - private final Long autonomousSystemNumber; - private final String autonomousSystemOrganization; - private final String ipAddress; - private final Network network; + @JsonProperty("autonomous_system_organization") + @MaxMindDbParameter(name = "autonomous_system_organization") + String autonomousSystemOrganization, - /** - * Constructs an instance of {@code AsnResponse} with the specified values for all fields. - * - * @param autonomousSystemNumber the autonomous system number associated with the IP - * address - * @param autonomousSystemOrganization the organization associated with the registered - * autonomous system number for the IP address - * @param ipAddress the IP address that the data in the model is for - * @param network the network associated with the record - */ - @MaxMindDbConstructor - public AsnResponse( - @JsonProperty("autonomous_system_number") - @MaxMindDbParameter(name = "autonomous_system_number") Long autonomousSystemNumber, - @JsonProperty("autonomous_system_organization") - @MaxMindDbParameter(name = "autonomous_system_organization") - String autonomousSystemOrganization, - @JsonProperty("ip_address") - @MaxMindDbParameter(name = "ip_address") String ipAddress, - @JsonProperty("network") - @JsonDeserialize(using = NetworkDeserializer.class) @MaxMindDbParameter(name = "network") - Network network - ) { - this.autonomousSystemNumber = autonomousSystemNumber; - this.autonomousSystemOrganization = autonomousSystemOrganization; - this.ipAddress = ipAddress; - this.network = network; - } + @JsonProperty("ip_address") + @MaxMindDbIpAddress + InetAddress ipAddress, - /** - * Constructs an instance of {@code AsnResponse} with only the specified values set. - * - * @param response The {@code AsnResponse} object to copy. - * @param ipAddress The IP address that the data in the model is for. - * @param network The network associated with the record. - */ - public AsnResponse( - AsnResponse response, - String ipAddress, - Network network - ) { - this( - response.getAutonomousSystemNumber(), - response.getAutonomousSystemOrganization(), - ipAddress, - network - ); - } + @JsonProperty("network") + @JsonDeserialize(using = NetworkDeserializer.class) + @MaxMindDbNetwork + Network network +) implements JsonSerializable { /** * @return The autonomous system number associated with the IP address. + * @deprecated Use {@link #autonomousSystemNumber()} instead. This method will be removed + * in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("autonomous_system_number") public Long getAutonomousSystemNumber() { - return this.autonomousSystemNumber; + return autonomousSystemNumber(); } /** * @return The organization associated with the registered autonomous system * number for the IP address + * @deprecated Use {@link #autonomousSystemOrganization()} instead. This method will be + * removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("autonomous_system_organization") public String getAutonomousSystemOrganization() { - return this.autonomousSystemOrganization; + return autonomousSystemOrganization(); } /** * @return The IP address that the data in the model is for. + * @deprecated Use {@link #ipAddress()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("ip_address") public String getIpAddress() { - return this.ipAddress; + return ipAddress().getHostAddress(); } /** * @return The network associated with the record. In particular, this is * the largest network where all the fields besides IP address have the * same value. + * @deprecated Use {@link #network()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty @JsonSerialize(using = ToStringSerializer.class) public Network getNetwork() { - return this.network; + return network(); } } diff --git a/src/main/java/com/maxmind/geoip2/model/CityResponse.java b/src/main/java/com/maxmind/geoip2/model/CityResponse.java index a9e64f65..f6f35254 100644 --- a/src/main/java/com/maxmind/geoip2/model/CityResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/CityResponse.java @@ -1,10 +1,9 @@ package com.maxmind.geoip2.model; -import com.fasterxml.jackson.annotation.JacksonInject; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import com.maxmind.db.MaxMindDbConstructor; import com.maxmind.db.MaxMindDbParameter; -import com.maxmind.db.Network; +import com.maxmind.geoip2.JsonSerializable; import com.maxmind.geoip2.record.City; import com.maxmind.geoip2.record.Continent; import com.maxmind.geoip2.record.Country; @@ -21,59 +20,278 @@ * This class provides a model for the data returned by the City Plus web * service and the City database. * + * @param city City record for the requested IP address. + * @param continent Continent record for the requested IP address. + * @param country Country record for the requested IP address. This object represents the country + * where MaxMind believes the end user is located. + * @param location Location record for the requested IP address. + * @param maxmind MaxMind record containing data related to your account. + * @param postal Postal record for the requested IP address. + * @param registeredCountry Registered country record for the requested IP address. This record + * represents the country where the ISP has registered a given IP block + * and may differ from the user's country. + * @param representedCountry Represented country record for the requested IP address. The + * represented country is used for things like military bases. It is + * only present when the represented country differs from the country. + * @param subdivisions An {@link List} of {@link Subdivision} objects representing the country + * subdivisions for the requested IP address. The number and type of + * subdivisions varies by country, but a subdivision is typically a state, + * province, county, etc. Subdivisions are ordered from most general (largest) + * to most specific (smallest). If the response did not contain any + * subdivisions, this is an empty list. + * @param traits Record for the traits of the requested IP address. * @see GeoIP2 Web * Services */ -public final class CityResponse extends AbstractCityResponse { +public record CityResponse( + @JsonProperty("city") + @MaxMindDbParameter(name = "city") + City city, + + @JsonProperty("continent") + @MaxMindDbParameter(name = "continent") + Continent continent, + + @JsonProperty("country") + @MaxMindDbParameter(name = "country") + Country country, + + @JsonProperty("location") + @MaxMindDbParameter(name = "location") + Location location, + + @JsonProperty("maxmind") + @MaxMindDbParameter(name = "maxmind") + MaxMind maxmind, + + @JsonProperty("postal") + @MaxMindDbParameter(name = "postal") + Postal postal, + + @JsonProperty("registered_country") + @MaxMindDbParameter(name = "registered_country") + Country registeredCountry, + + @JsonProperty("represented_country") + @MaxMindDbParameter(name = "represented_country") + RepresentedCountry representedCountry, + + @JsonProperty("subdivisions") + @MaxMindDbParameter(name = "subdivisions") + List subdivisions, + + @JsonProperty("traits") + @MaxMindDbParameter(name = "traits") + Traits traits +) implements JsonSerializable { + /** - * Constructs an instance of {@code CityResponse} with the specified parameters. - * - * @param city city - * @param continent continent - * @param country country - * @param location location - * @param maxmind maxmind record for the response - * @param postal postal - * @param registeredCountry registered country - * @param representedCountry represented country - * @param subdivisions subdivisions - * @param traits traits - */ - @MaxMindDbConstructor - public CityResponse( - @JsonProperty("city") @MaxMindDbParameter(name = "city") City city, - @JsonProperty("continent") @MaxMindDbParameter(name = "continent") Continent continent, - @JsonProperty("country") @MaxMindDbParameter(name = "country") Country country, - @JsonProperty("location") @MaxMindDbParameter(name = "location") Location location, - @JsonProperty("maxmind") @MaxMindDbParameter(name = "maxmind") MaxMind maxmind, - @JsonProperty("postal") @MaxMindDbParameter(name = "postal") Postal postal, - @JsonProperty("registered_country") @MaxMindDbParameter(name = "registered_country") - Country registeredCountry, - @JsonProperty("represented_country") @MaxMindDbParameter(name = "represented_country") - RepresentedCountry representedCountry, - @JsonProperty("subdivisions") @MaxMindDbParameter(name = "subdivisions") - ArrayList subdivisions, - @JsonProperty("traits") @MaxMindDbParameter(name = "traits") - Traits traits - ) { - super(city, continent, country, location, maxmind, postal, registeredCountry, - representedCountry, subdivisions, traits); + * Compact canonical constructor that sets defaults for null values. + */ + public CityResponse { + city = city != null ? city : new City(); + continent = continent != null ? continent : new Continent(); + country = country != null ? country : new Country(); + location = location != null ? location : new Location(); + maxmind = maxmind != null ? maxmind : new MaxMind(); + postal = postal != null ? postal : new Postal(); + registeredCountry = registeredCountry != null ? registeredCountry : new Country(); + representedCountry = representedCountry != null + ? representedCountry : new RepresentedCountry(); + subdivisions = subdivisions != null ? List.copyOf(subdivisions) : List.of(); + traits = traits != null ? traits : new Traits(); } /** * Constructs an instance of {@code CityResponse} with the specified parameters. * * @param response the response - * @param ipAddress the IP address that the data in the model is for. - * @param network the network associated with the record. * @param locales the locales */ public CityResponse( CityResponse response, - String ipAddress, - Network network, List locales ) { - super(response, ipAddress, network, locales); + this( + new City(response.city(), locales), + new Continent(response.continent(), locales), + new Country(response.country(), locales), + response.location(), + response.maxmind(), + response.postal(), + new Country(response.registeredCountry(), locales), + new RepresentedCountry(response.representedCountry(), locales), + mapSubdivisions(response.subdivisions(), locales), + response.traits() + ); + } + + private static ArrayList mapSubdivisions( + List subdivisions, + List locales + ) { + var subdivisions2 = new ArrayList(subdivisions.size()); + for (var subdivision : subdivisions) { + subdivisions2.add(new Subdivision(subdivision, locales)); + } + return subdivisions2; + } + + /** + * @return City record for the requested IP address. + * @deprecated Use {@link #city()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public City getCity() { + return city(); + } + + /** + * @return Continent record for the requested IP address. + * @deprecated Use {@link #continent()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Continent getContinent() { + return continent(); + } + + /** + * @return Country record for the requested IP address. This object + * represents the country where MaxMind believes the end user is + * located. + * @deprecated Use {@link #country()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Country getCountry() { + return country(); + } + + /** + * @return Location record for the requested IP address. + * @deprecated Use {@link #location()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Location getLocation() { + return location(); + } + + /** + * @return MaxMind record containing data related to your account. + * @deprecated Use {@link #maxmind()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("maxmind") + public MaxMind getMaxMind() { + return maxmind(); + } + + /** + * @return the postal + * @deprecated Use {@link #postal()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Postal getPostal() { + return postal(); + } + + /** + * @return Registered country record for the requested IP address. This + * record represents the country where the ISP has registered a + * given IP block and may differ from the user's country. + * @deprecated Use {@link #registeredCountry()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("registered_country") + public Country getRegisteredCountry() { + return registeredCountry(); + } + + /** + * @return Represented country record for the requested IP address. The + * represented country is used for things like military bases. It is + * only present when the represented country differs from the + * country. + * @deprecated Use {@link #representedCountry()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("represented_country") + public RepresentedCountry getRepresentedCountry() { + return representedCountry(); + } + + /** + * @return An {@link List} of {@link Subdivision} objects representing the + * country subdivisions for the requested IP address. The number and + * type of subdivisions varies by country, but a subdivision is + * typically a state, province, county, etc. Subdivisions are + * ordered from most general (largest) to most specific (smallest). + * If the response did not contain any subdivisions, this method + * returns an empty array. + * @deprecated Use {@link #subdivisions()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public List getSubdivisions() { + return new ArrayList<>(subdivisions()); + } + + /** + * @return Record for the traits of the requested IP address. + * @deprecated Use {@link #traits()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Traits getTraits() { + return traits(); + } + + /** + * @return An object representing the most specific subdivision returned. If + * the response did not contain any subdivisions, this method + * returns an empty {@link Subdivision} object. + */ + @JsonIgnore + public Subdivision mostSpecificSubdivision() { + if (subdivisions().isEmpty()) { + return new Subdivision(); + } + return subdivisions().get(subdivisions().size() - 1); + } + + /** + * @return An object representing the most specific subdivision returned. If + * the response did not contain any subdivisions, this method + * returns an empty {@link Subdivision} object. + * @deprecated Use {@link #mostSpecificSubdivision()} instead. This method will be removed + * in 6.0.0. + */ + @JsonIgnore + @Deprecated(since = "5.0.0", forRemoval = true) + public Subdivision getMostSpecificSubdivision() { + return mostSpecificSubdivision(); + } + + /** + * @return An object representing the least specific subdivision returned. If + * the response did not contain any subdivisions, this method + * returns an empty {@link Subdivision} object. + */ + @JsonIgnore + public Subdivision leastSpecificSubdivision() { + if (subdivisions().isEmpty()) { + return new Subdivision(); + } + return subdivisions().get(0); + } + + /** + * @return An object representing the least specific subdivision returned. If + * the response did not contain any subdivisions, this method + * returns an empty {@link Subdivision} object. + * @deprecated Use {@link #leastSpecificSubdivision()} instead. This method will be removed + * in 6.0.0. + */ + @JsonIgnore + @Deprecated(since = "5.0.0", forRemoval = true) + public Subdivision getLeastSpecificSubdivision() { + return leastSpecificSubdivision(); } } diff --git a/src/main/java/com/maxmind/geoip2/model/ConnectionTypeResponse.java b/src/main/java/com/maxmind/geoip2/model/ConnectionTypeResponse.java index 06c956f7..40b492c9 100644 --- a/src/main/java/com/maxmind/geoip2/model/ConnectionTypeResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/ConnectionTypeResponse.java @@ -1,21 +1,42 @@ package com.maxmind.geoip2.model; -import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; -import com.maxmind.db.MaxMindDbConstructor; +import com.maxmind.db.MaxMindDbCreator; +import com.maxmind.db.MaxMindDbIpAddress; +import com.maxmind.db.MaxMindDbNetwork; import com.maxmind.db.MaxMindDbParameter; import com.maxmind.db.Network; +import com.maxmind.geoip2.JsonSerializable; import com.maxmind.geoip2.NetworkDeserializer; +import java.net.InetAddress; /** * This class provides the GeoIP2 Connection-Type model. + * + * @param connectionType The connection type of the IP address. + * @param ipAddress The IP address that the data in the model is for. + * @param network The network associated with the record. In particular, this is the largest + * network where all the fields besides IP address have the same value. */ -public class ConnectionTypeResponse extends AbstractResponse { +public record ConnectionTypeResponse( + @JsonProperty("connection_type") + @MaxMindDbParameter(name = "connection_type") + ConnectionType connectionType, + + @JsonProperty("ip_address") + @MaxMindDbIpAddress + InetAddress ipAddress, + + @JsonProperty("network") + @JsonDeserialize(using = NetworkDeserializer.class) + @MaxMindDbNetwork + Network network +) implements JsonSerializable { /** * The enumerated values that connection-type may take. @@ -50,6 +71,7 @@ public String toString() { * @param s The string to create the instance from. */ @JsonCreator + @MaxMindDbCreator public static ConnectionType fromString(String s) { if (s == null) { return null; @@ -66,91 +88,36 @@ public static ConnectionType fromString(String s) { } } - private final ConnectionType connectionType; - private final String ipAddress; - private final Network network; - - /** - * Constructs an instance of {@code ConnectionTypeResponse}. - * - * @param connectionType The connection type of the IP address. - * @param ipAddress The IP address that the data in the model is for. - * @param network The network associated with the record. - */ - public ConnectionTypeResponse( - @JsonProperty("connection_type") ConnectionType connectionType, - @JsonProperty("ip_address") String ipAddress, - @JsonProperty("network") - @JsonDeserialize(using = NetworkDeserializer.class) Network network - ) { - this.connectionType = connectionType; - this.ipAddress = ipAddress; - this.network = network; - } - - /** - * Constructs an instance of {@code ConnectionTypeResponse}. - * - * @param connectionType The connection type of the IP address. - * @param ipAddress The IP address that the data in the model is for. - * @param network The network associated with the record. - */ - @MaxMindDbConstructor - public ConnectionTypeResponse( - @MaxMindDbParameter(name = "connection_type") String connectionType, - @MaxMindDbParameter(name = "ip_address") String ipAddress, - @MaxMindDbParameter(name = "network") Network network - ) { - this( - ConnectionType.fromString(connectionType), - ipAddress, - network - ); - } - - /** - * Constructs an instance of {@code ConnectionTypeResponse}. - * - * @param response The {@code ConnectionTypeResponse} object to copy. - * @param ipAddress The IP address that the data in the model is for. - * @param network The network associated with the record. - */ - public ConnectionTypeResponse( - ConnectionTypeResponse response, - String ipAddress, - Network network - ) { - this( - response.getConnectionType(), - ipAddress, - network - ); - } - /** * @return The connection type of the IP address. + * @deprecated Use {@link #connectionType()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("connection_type") public ConnectionType getConnectionType() { - return this.connectionType; + return connectionType(); } /** * @return The IP address that the data in the model is for. + * @deprecated Use {@link #ipAddress()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("ip_address") public String getIpAddress() { - return this.ipAddress; + return ipAddress().getHostAddress(); } /** * @return The network associated with the record. In particular, this is * the largest network where all the fields besides IP address have the * same value. + * @deprecated Use {@link #network()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty @JsonSerialize(using = ToStringSerializer.class) public Network getNetwork() { - return this.network; + return network(); } } diff --git a/src/main/java/com/maxmind/geoip2/model/CountryResponse.java b/src/main/java/com/maxmind/geoip2/model/CountryResponse.java index 364c9bc6..23c3c3f2 100644 --- a/src/main/java/com/maxmind/geoip2/model/CountryResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/CountryResponse.java @@ -1,10 +1,8 @@ package com.maxmind.geoip2.model; -import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonProperty; -import com.maxmind.db.MaxMindDbConstructor; import com.maxmind.db.MaxMindDbParameter; -import com.maxmind.db.Network; +import com.maxmind.geoip2.JsonSerializable; import com.maxmind.geoip2.record.Continent; import com.maxmind.geoip2.record.Country; import com.maxmind.geoip2.record.MaxMind; @@ -16,50 +14,140 @@ * This class provides a model for the data returned by the Country web service * and the Country database. * + * @param continent Continent record for the requested IP address. + * @param country Country record for the requested IP address. This object represents the country + * where MaxMind believes the end user is located. + * @param maxmind MaxMind record containing data related to your account. + * @param registeredCountry Registered country record for the requested IP address. This record + * represents the country where the ISP has registered a given IP block + * and may differ from the user's country. + * @param representedCountry Represented country record for the requested IP address. The + * represented country is used for things like military bases. It is + * only present when the represented country differs from the country. + * @param traits Record for the traits of the requested IP address. * @see GeoIP2 Web * Services */ -public final class CountryResponse extends AbstractCountryResponse { +public record CountryResponse( + @JsonProperty("continent") + @MaxMindDbParameter(name = "continent") + Continent continent, + + @JsonProperty("country") + @MaxMindDbParameter(name = "country") + Country country, + + @JsonProperty("maxmind") + @MaxMindDbParameter(name = "maxmind") + MaxMind maxmind, + + @JsonProperty("registered_country") + @MaxMindDbParameter(name = "registered_country") + Country registeredCountry, + + @JsonProperty("represented_country") + @MaxMindDbParameter(name = "represented_country") + RepresentedCountry representedCountry, + + @JsonProperty("traits") + @MaxMindDbParameter(name = "traits") + Traits traits +) implements JsonSerializable { /** - * Constructs an instance of {@code CountryResponse} with the specified parameters. - * - * @param continent the continent - * @param country the country - * @param maxmind the MaxMind record - * @param registeredCountry the registered country - * @param representedCountry the represented country - * @param traits the traits + * Compact canonical constructor that sets defaults for null values. */ - @MaxMindDbConstructor - public CountryResponse( - @JsonProperty("continent") @MaxMindDbParameter(name = "continent") Continent continent, - @JsonProperty("country") @MaxMindDbParameter(name = "country") Country country, - @JsonProperty("maxmind") @MaxMindDbParameter(name = "maxmind") MaxMind maxmind, - @JsonProperty("registered_country") @MaxMindDbParameter(name = "registered_country") - Country registeredCountry, - @JsonProperty("represented_country") @MaxMindDbParameter(name = "represented_country") - RepresentedCountry representedCountry, - @JsonProperty("traits") @MaxMindDbParameter(name = "traits") - Traits traits - ) { - super(continent, country, maxmind, registeredCountry, representedCountry, traits); + public CountryResponse { + continent = continent != null ? continent : new Continent(); + country = country != null ? country : new Country(); + maxmind = maxmind != null ? maxmind : new MaxMind(); + registeredCountry = registeredCountry != null ? registeredCountry : new Country(); + representedCountry = representedCountry != null + ? representedCountry : new RepresentedCountry(); + traits = traits != null ? traits : new Traits(); } /** * Constructs an instance of {@code CountryResponse} with the specified parameters. * * @param response the response - * @param ipAddress the IP address that the data in the model is for. - * @param network the network associated with the record. * @param locales the locales */ public CountryResponse( CountryResponse response, - String ipAddress, - Network network, List locales ) { - super(response, ipAddress, network, locales); + this( + new Continent(response.continent(), locales), + new Country(response.country(), locales), + response.maxmind(), + new Country(response.registeredCountry(), locales), + new RepresentedCountry(response.representedCountry(), locales), + response.traits() + ); + } + + /** + * @return MaxMind record containing data related to your account. + * @deprecated Use {@link #maxmind()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("maxmind") + public MaxMind getMaxMind() { + return maxmind(); + } + + /** + * @return Registered country record for the requested IP address. This + * record represents the country where the ISP has registered a + * given IP block and may differ from the user's country. + * @deprecated Use {@link #registeredCountry()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("registered_country") + public Country getRegisteredCountry() { + return registeredCountry(); + } + + /** + * @return Continent record for the requested IP address. + * @deprecated Use {@link #continent()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Continent getContinent() { + return continent(); + } + + /** + * @return Country record for the requested IP address. This object + * represents the country where MaxMind believes the end user is + * located. + * @deprecated Use {@link #country()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Country getCountry() { + return country(); + } + + /** + * @return Represented country record for the requested IP address. The + * represented country is used for things like military bases. It is + * only present when the represented country differs from the + * country. + * @deprecated Use {@link #representedCountry()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("represented_country") + public RepresentedCountry getRepresentedCountry() { + return representedCountry(); + } + + /** + * @return Record for the traits of the requested IP address. + * @deprecated Use {@link #traits()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Traits getTraits() { + return traits(); } } diff --git a/src/main/java/com/maxmind/geoip2/model/DomainResponse.java b/src/main/java/com/maxmind/geoip2/model/DomainResponse.java index 81b12987..347f255c 100644 --- a/src/main/java/com/maxmind/geoip2/model/DomainResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/DomainResponse.java @@ -1,85 +1,72 @@ package com.maxmind.geoip2.model; -import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; -import com.maxmind.db.MaxMindDbConstructor; +import com.maxmind.db.MaxMindDbIpAddress; +import com.maxmind.db.MaxMindDbNetwork; import com.maxmind.db.MaxMindDbParameter; import com.maxmind.db.Network; +import com.maxmind.geoip2.JsonSerializable; import com.maxmind.geoip2.NetworkDeserializer; +import java.net.InetAddress; /** * This class provides the GeoIP2 Domain model. + * + * @param domain The second level domain associated with the IP address. This will be something + * like "example.com" or "example.co.uk", not "foo.example.com". + * @param ipAddress The IP address that the data in the model is for. + * @param network The network associated with the record. In particular, this is the largest + * network where all the fields besides IP address have the same value. */ -public class DomainResponse extends AbstractResponse { +public record DomainResponse( + @JsonProperty("domain") + @MaxMindDbParameter(name = "domain") + String domain, - private final String domain; - private final String ipAddress; - private final Network network; - - /** - * Constructs an instance of {@code DomainResponse}. - * - * @param domain the second level domain associated with the IP address - * @param ipAddress the IP address that the data in the model is for - * @param network the network associated with the record - */ - @MaxMindDbConstructor - public DomainResponse( - @JsonProperty("domain") @MaxMindDbParameter(name = "domain") String domain, - @JsonProperty("ip_address") - @MaxMindDbParameter(name = "ip_address") String ipAddress, - @JsonProperty("network") - @JsonDeserialize(using = NetworkDeserializer.class) @MaxMindDbParameter(name = "network") - Network network - ) { - this.domain = domain; - this.ipAddress = ipAddress; - this.network = network; - } + @JsonProperty("ip_address") + @MaxMindDbIpAddress + InetAddress ipAddress, - /** - * Constructs an instance of {@code DomainResponse} with only required parameters. - * - * @param response the response - * @param ipAddress the IP address that the data in the model is for. - * @param network the network associated with the record. - */ - public DomainResponse( - DomainResponse response, - String ipAddress, - Network network - ) { - this(response.getDomain(), ipAddress, network); - } + @JsonProperty("network") + @JsonDeserialize(using = NetworkDeserializer.class) + @MaxMindDbNetwork + Network network +) implements JsonSerializable { /** * @return The second level domain associated with the IP address. This * will be something like "example.com" or "example.co.uk", not * "foo.example.com". + * @deprecated Use {@link #domain()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) public String getDomain() { - return this.domain; + return domain(); } /** * @return The IP address that the data in the model is for. + * @deprecated Use {@link #ipAddress()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("ip_address") public String getIpAddress() { - return this.ipAddress; + return ipAddress().getHostAddress(); } /** * @return The network associated with the record. In particular, this is * the largest network where all the fields besides IP address have the * same value. + * @deprecated Use {@link #network()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty @JsonSerialize(using = ToStringSerializer.class) public Network getNetwork() { - return this.network; + return network(); } } diff --git a/src/main/java/com/maxmind/geoip2/model/EnterpriseResponse.java b/src/main/java/com/maxmind/geoip2/model/EnterpriseResponse.java index 700c025f..5cc60ef6 100644 --- a/src/main/java/com/maxmind/geoip2/model/EnterpriseResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/EnterpriseResponse.java @@ -1,10 +1,9 @@ package com.maxmind.geoip2.model; -import com.fasterxml.jackson.annotation.JacksonInject; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import com.maxmind.db.MaxMindDbConstructor; import com.maxmind.db.MaxMindDbParameter; -import com.maxmind.db.Network; +import com.maxmind.geoip2.JsonSerializable; import com.maxmind.geoip2.record.City; import com.maxmind.geoip2.record.Continent; import com.maxmind.geoip2.record.Country; @@ -22,58 +21,277 @@ * This class provides a model for the data returned by the GeoIP2 Enterprise * database *

+ * + * @param city City record for the requested IP address. + * @param continent Continent record for the requested IP address. + * @param country Country record for the requested IP address. This object represents the country + * where MaxMind believes the end user is located. + * @param location Location record for the requested IP address. + * @param maxmind MaxMind record containing data related to your account. + * @param postal Postal record for the requested IP address. + * @param registeredCountry Registered country record for the requested IP address. This record + * represents the country where the ISP has registered a given IP block + * and may differ from the user's country. + * @param representedCountry Represented country record for the requested IP address. The + * represented country is used for things like military bases. It is + * only present when the represented country differs from the country. + * @param subdivisions An {@link List} of {@link Subdivision} objects representing the country + * subdivisions for the requested IP address. The number and type of + * subdivisions varies by country, but a subdivision is typically a state, + * province, county, etc. Subdivisions are ordered from most general (largest) + * to most specific (smallest). If the response did not contain any + * subdivisions, this is an empty list. + * @param traits Record for the traits of the requested IP address. */ -public final class EnterpriseResponse extends AbstractCityResponse { +public record EnterpriseResponse( + @JsonProperty("city") + @MaxMindDbParameter(name = "city") + City city, + + @JsonProperty("continent") + @MaxMindDbParameter(name = "continent") + Continent continent, + + @JsonProperty("country") + @MaxMindDbParameter(name = "country") + Country country, + + @JsonProperty("location") + @MaxMindDbParameter(name = "location") + Location location, + + @JsonProperty("maxmind") + @MaxMindDbParameter(name = "maxmind") + MaxMind maxmind, + + @JsonProperty("postal") + @MaxMindDbParameter(name = "postal") + Postal postal, + + @JsonProperty("registered_country") + @MaxMindDbParameter(name = "registered_country") + Country registeredCountry, + + @JsonProperty("represented_country") + @MaxMindDbParameter(name = "represented_country") + RepresentedCountry representedCountry, + + @JsonProperty("subdivisions") + @MaxMindDbParameter(name = "subdivisions") + List subdivisions, + + @JsonProperty("traits") + @MaxMindDbParameter(name = "traits") + Traits traits +) implements JsonSerializable { /** - * Constructs an instance of {@code EnterpriseResponse} with the specified parameters. - * - * @param city city - * @param continent continent - * @param country country - * @param location location - * @param maxmind maxmind record for the response - * @param postal postal - * @param registeredCountry registered country - * @param representedCountry represented country - * @param subdivisions subdivisions - * @param traits traits - */ - @MaxMindDbConstructor - public EnterpriseResponse( - @JsonProperty("city") @MaxMindDbParameter(name = "city") City city, - @JsonProperty("continent") @MaxMindDbParameter(name = "continent") Continent continent, - @JsonProperty("country") @MaxMindDbParameter(name = "country") Country country, - @JsonProperty("location") @MaxMindDbParameter(name = "location") Location location, - @JsonProperty("maxmind") @MaxMindDbParameter(name = "maxmind") MaxMind maxmind, - @JsonProperty("postal") @MaxMindDbParameter(name = "postal") Postal postal, - @JsonProperty("registered_country") @MaxMindDbParameter(name = "registered_country") - Country registeredCountry, - @JsonProperty("represented_country") @MaxMindDbParameter(name = "represented_country") - RepresentedCountry representedCountry, - @JsonProperty("subdivisions") @MaxMindDbParameter(name = "subdivisions") - ArrayList subdivisions, - @JsonProperty("traits") @MaxMindDbParameter(name = "traits") - Traits traits - ) { - super(city, continent, country, location, maxmind, postal, registeredCountry, - representedCountry, subdivisions, traits); + * Compact canonical constructor that sets defaults for null values. + */ + public EnterpriseResponse { + city = city != null ? city : new City(); + continent = continent != null ? continent : new Continent(); + country = country != null ? country : new Country(); + location = location != null ? location : new Location(); + maxmind = maxmind != null ? maxmind : new MaxMind(); + postal = postal != null ? postal : new Postal(); + registeredCountry = registeredCountry != null ? registeredCountry : new Country(); + representedCountry = representedCountry != null + ? representedCountry : new RepresentedCountry(); + subdivisions = subdivisions != null ? List.copyOf(subdivisions) : List.of(); + traits = traits != null ? traits : new Traits(); } /** * Constructs an instance of {@code EnterpriseResponse} with only required parameters. * * @param response the response - * @param ipAddress the IP address that the data in the model is for. - * @param network the network associated with the record. * @param locales the locales */ public EnterpriseResponse( EnterpriseResponse response, - String ipAddress, - Network network, List locales ) { - super(response, ipAddress, network, locales); + this( + new City(response.city(), locales), + new Continent(response.continent(), locales), + new Country(response.country(), locales), + response.location(), + response.maxmind(), + response.postal(), + new Country(response.registeredCountry(), locales), + new RepresentedCountry(response.representedCountry(), locales), + mapSubdivisions(response.subdivisions(), locales), + response.traits() + ); + } + + private static ArrayList mapSubdivisions( + List subdivisions, + List locales + ) { + var subdivisions2 = new ArrayList(subdivisions.size()); + for (var subdivision : subdivisions) { + subdivisions2.add(new Subdivision(subdivision, locales)); + } + return subdivisions2; + } + + /** + * @return City record for the requested IP address. + * @deprecated Use {@link #city()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public City getCity() { + return city(); + } + + /** + * @return Continent record for the requested IP address. + * @deprecated Use {@link #continent()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Continent getContinent() { + return continent(); + } + + /** + * @return Country record for the requested IP address. This object + * represents the country where MaxMind believes the end user is + * located. + * @deprecated Use {@link #country()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Country getCountry() { + return country(); + } + + /** + * @return Location record for the requested IP address. + * @deprecated Use {@link #location()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Location getLocation() { + return location(); + } + + /** + * @return MaxMind record containing data related to your account. + * @deprecated Use {@link #maxmind()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("maxmind") + public MaxMind getMaxMind() { + return maxmind(); + } + + /** + * @return the postal + * @deprecated Use {@link #postal()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Postal getPostal() { + return postal(); + } + + /** + * @return Registered country record for the requested IP address. This + * record represents the country where the ISP has registered a + * given IP block and may differ from the user's country. + * @deprecated Use {@link #registeredCountry()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("registered_country") + public Country getRegisteredCountry() { + return registeredCountry(); + } + + /** + * @return Represented country record for the requested IP address. The + * represented country is used for things like military bases. It is + * only present when the represented country differs from the + * country. + * @deprecated Use {@link #representedCountry()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("represented_country") + public RepresentedCountry getRepresentedCountry() { + return representedCountry(); + } + + /** + * @return An {@link List} of {@link Subdivision} objects representing the + * country subdivisions for the requested IP address. The number and + * type of subdivisions varies by country, but a subdivision is + * typically a state, province, county, etc. Subdivisions are + * ordered from most general (largest) to most specific (smallest). + * If the response did not contain any subdivisions, this method + * returns an empty array. + * @deprecated Use {@link #subdivisions()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public List getSubdivisions() { + return new ArrayList<>(subdivisions()); + } + + /** + * @return Record for the traits of the requested IP address. + * @deprecated Use {@link #traits()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Traits getTraits() { + return traits(); + } + + /** + * @return An object representing the most specific subdivision returned. If + * the response did not contain any subdivisions, this method + * returns an empty {@link Subdivision} object. + */ + @JsonIgnore + public Subdivision mostSpecificSubdivision() { + if (subdivisions().isEmpty()) { + return new Subdivision(); + } + return subdivisions().get(subdivisions().size() - 1); + } + + /** + * @return An object representing the most specific subdivision returned. If + * the response did not contain any subdivisions, this method + * returns an empty {@link Subdivision} object. + * @deprecated Use {@link #mostSpecificSubdivision()} instead. This method will be removed + * in 6.0.0. + */ + @JsonIgnore + @Deprecated(since = "5.0.0", forRemoval = true) + public Subdivision getMostSpecificSubdivision() { + return mostSpecificSubdivision(); + } + + /** + * @return An object representing the least specific subdivision returned. If + * the response did not contain any subdivisions, this method + * returns an empty {@link Subdivision} object. + */ + @JsonIgnore + public Subdivision leastSpecificSubdivision() { + if (subdivisions().isEmpty()) { + return new Subdivision(); + } + return subdivisions().get(0); + } + + /** + * @return An object representing the least specific subdivision returned. If + * the response did not contain any subdivisions, this method + * returns an empty {@link Subdivision} object. + * @deprecated Use {@link #leastSpecificSubdivision()} instead. This method will be removed + * in 6.0.0. + */ + @JsonIgnore + @Deprecated(since = "5.0.0", forRemoval = true) + public Subdivision getLeastSpecificSubdivision() { + return leastSpecificSubdivision(); } } diff --git a/src/main/java/com/maxmind/geoip2/model/InsightsResponse.java b/src/main/java/com/maxmind/geoip2/model/InsightsResponse.java index b96bceb7..2358153e 100644 --- a/src/main/java/com/maxmind/geoip2/model/InsightsResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/InsightsResponse.java @@ -1,7 +1,8 @@ package com.maxmind.geoip2.model; -import com.fasterxml.jackson.annotation.JacksonInject; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import com.maxmind.geoip2.JsonSerializable; import com.maxmind.geoip2.record.City; import com.maxmind.geoip2.record.Continent; import com.maxmind.geoip2.record.Country; @@ -11,43 +12,240 @@ import com.maxmind.geoip2.record.RepresentedCountry; import com.maxmind.geoip2.record.Subdivision; import com.maxmind.geoip2.record.Traits; +import java.util.ArrayList; import java.util.List; /** * This class provides a model for the data returned by the Insights web * service. * + * @param city City record for the requested IP address. + * @param continent Continent record for the requested IP address. + * @param country Country record for the requested IP address. This object represents the country + * where MaxMind believes the end user is located. + * @param location Location record for the requested IP address. + * @param maxmind MaxMind record containing data related to your account. + * @param postal Postal record for the requested IP address. + * @param registeredCountry Registered country record for the requested IP address. This record + * represents the country where the ISP has registered a given IP block + * and may differ from the user's country. + * @param representedCountry Represented country record for the requested IP address. The + * represented country is used for things like military bases. It is + * only present when the represented country differs from the country. + * @param subdivisions An {@link List} of {@link Subdivision} objects representing the country + * subdivisions for the requested IP address. The number and type of + * subdivisions varies by country, but a subdivision is typically a state, + * province, county, etc. Subdivisions are ordered from most general (largest) + * to most specific (smallest). If the response did not contain any + * subdivisions, this is an empty list. + * @param traits Record for the traits of the requested IP address. * @see GeoIP2 Web * Services */ -public class InsightsResponse extends AbstractCityResponse { - /** - * Constructs an instance of {@code InsightsResponse} with the specified parameters. - * - * @param city city - * @param continent continent - * @param country country - * @param location location - * @param maxmind maxmind record for the response - * @param postal postal - * @param registeredCountry registered country - * @param representedCountry represented country - * @param subdivisions subdivisions - * @param traits traits - */ - public InsightsResponse( - @JsonProperty("city") City city, - @JsonProperty("continent") Continent continent, - @JsonProperty("country") Country country, - @JsonProperty("location") Location location, - @JsonProperty("maxmind") MaxMind maxmind, - @JsonProperty("postal") Postal postal, - @JsonProperty("registered_country") Country registeredCountry, - @JsonProperty("represented_country") RepresentedCountry representedCountry, - @JsonProperty("subdivisions") List subdivisions, - @JsonProperty("traits") Traits traits - ) { - super(city, continent, country, location, maxmind, postal, registeredCountry, - representedCountry, subdivisions, traits); +public record InsightsResponse( + @JsonProperty("city") + City city, + + @JsonProperty("continent") + Continent continent, + + @JsonProperty("country") + Country country, + + @JsonProperty("location") + Location location, + + @JsonProperty("maxmind") + MaxMind maxmind, + + @JsonProperty("postal") + Postal postal, + + @JsonProperty("registered_country") + Country registeredCountry, + + @JsonProperty("represented_country") + RepresentedCountry representedCountry, + + @JsonProperty("subdivisions") + List subdivisions, + + @JsonProperty("traits") + Traits traits +) implements JsonSerializable { + + /** + * Compact canonical constructor that sets defaults for null values. + */ + public InsightsResponse { + city = city != null ? city : new City(); + continent = continent != null ? continent : new Continent(); + country = country != null ? country : new Country(); + location = location != null ? location : new Location(); + maxmind = maxmind != null ? maxmind : new MaxMind(); + postal = postal != null ? postal : new Postal(); + registeredCountry = registeredCountry != null ? registeredCountry : new Country(); + representedCountry = representedCountry != null + ? representedCountry : new RepresentedCountry(); + subdivisions = subdivisions != null ? List.copyOf(subdivisions) : List.of(); + traits = traits != null ? traits : new Traits(); + } + + /** + * @return City record for the requested IP address. + * @deprecated Use {@link #city()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public City getCity() { + return city(); + } + + /** + * @return Continent record for the requested IP address. + * @deprecated Use {@link #continent()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Continent getContinent() { + return continent(); + } + + /** + * @return Country record for the requested IP address. This object + * represents the country where MaxMind believes the end user is + * located. + * @deprecated Use {@link #country()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Country getCountry() { + return country(); + } + + /** + * @return Location record for the requested IP address. + * @deprecated Use {@link #location()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Location getLocation() { + return location(); + } + + /** + * @return MaxMind record containing data related to your account. + * @deprecated Use {@link #maxmind()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("maxmind") + public MaxMind getMaxMind() { + return maxmind(); + } + + /** + * @return the postal + * @deprecated Use {@link #postal()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Postal getPostal() { + return postal(); + } + + /** + * @return Registered country record for the requested IP address. This + * record represents the country where the ISP has registered a + * given IP block and may differ from the user's country. + * @deprecated Use {@link #registeredCountry()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("registered_country") + public Country getRegisteredCountry() { + return registeredCountry(); + } + + /** + * @return Represented country record for the requested IP address. The + * represented country is used for things like military bases. It is + * only present when the represented country differs from the + * country. + * @deprecated Use {@link #representedCountry()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("represented_country") + public RepresentedCountry getRepresentedCountry() { + return representedCountry(); + } + + /** + * @return An {@link List} of {@link Subdivision} objects representing the + * country subdivisions for the requested IP address. The number and + * type of subdivisions varies by country, but a subdivision is + * typically a state, province, county, etc. Subdivisions are + * ordered from most general (largest) to most specific (smallest). + * If the response did not contain any subdivisions, this method + * returns an empty array. + * @deprecated Use {@link #subdivisions()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public List getSubdivisions() { + return new ArrayList<>(subdivisions()); + } + + /** + * @return Record for the traits of the requested IP address. + * @deprecated Use {@link #traits()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Traits getTraits() { + return traits(); + } + + /** + * @return An object representing the most specific subdivision returned. If + * the response did not contain any subdivisions, this method + * returns an empty {@link Subdivision} object. + */ + @JsonIgnore + public Subdivision mostSpecificSubdivision() { + if (subdivisions().isEmpty()) { + return new Subdivision(); + } + return subdivisions().get(subdivisions().size() - 1); + } + + /** + * @return An object representing the most specific subdivision returned. If + * the response did not contain any subdivisions, this method + * returns an empty {@link Subdivision} object. + * @deprecated Use {@link #mostSpecificSubdivision()} instead. This method will be removed + * in 6.0.0. + */ + @JsonIgnore + @Deprecated(since = "5.0.0", forRemoval = true) + public Subdivision getMostSpecificSubdivision() { + return mostSpecificSubdivision(); + } + + /** + * @return An object representing the least specific subdivision returned. If + * the response did not contain any subdivisions, this method + * returns an empty {@link Subdivision} object. + */ + @JsonIgnore + public Subdivision leastSpecificSubdivision() { + if (subdivisions().isEmpty()) { + return new Subdivision(); + } + return subdivisions().get(0); + } + + /** + * @return An object representing the least specific subdivision returned. If + * the response did not contain any subdivisions, this method + * returns an empty {@link Subdivision} object. + * @deprecated Use {@link #leastSpecificSubdivision()} instead. This method will be removed + * in 6.0.0. + */ + @JsonIgnore + @Deprecated(since = "5.0.0", forRemoval = true) + public Subdivision getLeastSpecificSubdivision() { + return leastSpecificSubdivision(); } } diff --git a/src/main/java/com/maxmind/geoip2/model/IpBaseResponse.java b/src/main/java/com/maxmind/geoip2/model/IpBaseResponse.java deleted file mode 100644 index fa3f65d3..00000000 --- a/src/main/java/com/maxmind/geoip2/model/IpBaseResponse.java +++ /dev/null @@ -1,125 +0,0 @@ -package com.maxmind.geoip2.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; -import com.maxmind.db.Network; - -/** - * This class provides the base IP model. - */ -public class IpBaseResponse extends AbstractResponse { - - private final boolean isAnonymous; - private final boolean isAnonymousVpn; - private final boolean isHostingProvider; - private final boolean isPublicProxy; - private final boolean isResidentialProxy; - private final boolean isTorExitNode; - private final String ipAddress; - private final Network network; - - /** - * Constructs an instance of {@code IpBaseResponse}. - * - * @param ipAddress the IP address that the data in the model is for - * @param isAnonymous whether the IP address belongs to any sort of anonymous network - * @param isAnonymousVpn whether the IP address belongs to an anonymous VPN system - * @param isHostingProvider whether the IP address belongs to a hosting provider - * @param isPublicProxy whether the IP address belongs to a public proxy system - * @param isResidentialProxy whether the IP address belongs to a residential proxy system - * @param isTorExitNode whether the IP address is a Tor exit node - * @param network the network associated with the record - */ - public IpBaseResponse( - String ipAddress, - boolean isAnonymous, - boolean isAnonymousVpn, - boolean isHostingProvider, - boolean isPublicProxy, - boolean isResidentialProxy, - boolean isTorExitNode, - Network network - ) { - this.isAnonymous = isAnonymous; - this.isAnonymousVpn = isAnonymousVpn; - this.isHostingProvider = isHostingProvider; - this.isPublicProxy = isPublicProxy; - this.isResidentialProxy = isResidentialProxy; - this.isTorExitNode = isTorExitNode; - this.ipAddress = ipAddress; - this.network = network; - } - - /** - * @return whether the IP address belongs to any sort of anonymous network. - */ - @JsonProperty("is_anonymous") - public boolean isAnonymous() { - return isAnonymous; - } - - /** - * @return whether the IP address is registered to an anonymous VPN - * provider. If a VPN provider does not register subnets under names - * associated with them, we will likely only flag their IP ranges using - * isHostingProvider. - */ - @JsonProperty("is_anonymous_vpn") - public boolean isAnonymousVpn() { - return isAnonymousVpn; - } - - /** - * @return whether the IP address belongs to a hosting or VPN provider - * (see description of isAnonymousVpn). - */ - @JsonProperty("is_hosting_provider") - public boolean isHostingProvider() { - return isHostingProvider; - } - - /** - * @return whether the IP address belongs to a public proxy. - */ - @JsonProperty("is_public_proxy") - public boolean isPublicProxy() { - return isPublicProxy; - } - - /** - * @return whether the IP address is on a suspected anonymizing network and - * belongs to a residential ISP. - */ - @JsonProperty("is_residential_proxy") - public boolean isResidentialProxy() { - return isResidentialProxy; - } - - /** - * @return whether the IP address is a Tor exit node. - */ - @JsonProperty("is_tor_exit_node") - public boolean isTorExitNode() { - return isTorExitNode; - } - - /** - * @return The IP address that the data in the model is for. - */ - @JsonProperty("ip_address") - public String getIpAddress() { - return this.ipAddress; - } - - /** - * @return The network associated with the record. In particular, this is - * the largest network where all the fields besides IP address have the - * same value. - */ - @JsonProperty - @JsonSerialize(using = ToStringSerializer.class) - public Network getNetwork() { - return this.network; - } -} diff --git a/src/main/java/com/maxmind/geoip2/model/IpRiskResponse.java b/src/main/java/com/maxmind/geoip2/model/IpRiskResponse.java index 4d66c694..4795ae18 100644 --- a/src/main/java/com/maxmind/geoip2/model/IpRiskResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/IpRiskResponse.java @@ -1,122 +1,104 @@ package com.maxmind.geoip2.model; -import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.maxmind.db.MaxMindDbConstructor; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.maxmind.db.MaxMindDbIpAddress; +import com.maxmind.db.MaxMindDbNetwork; import com.maxmind.db.MaxMindDbParameter; import com.maxmind.db.Network; +import com.maxmind.geoip2.JsonSerializable; import com.maxmind.geoip2.NetworkDeserializer; +import java.net.InetAddress; /** * This class provides the GeoIP2 IP Risk model. * + * @param ipAddress The IP address that the data in the model is for. + * @param isAnonymous Whether the IP address belongs to any sort of anonymous network. + * @param isAnonymousVpn Whether the IP address is registered to an anonymous VPN provider. If a + * VPN provider does not register subnets under names associated with them, + * we will likely only flag their IP ranges using isHostingProvider. + * @param isHostingProvider Whether the IP address belongs to a hosting or VPN provider (see + * description of isAnonymousVpn). + * @param isPublicProxy Whether the IP address belongs to a public proxy. + * @param isResidentialProxy Whether the IP address is on a suspected anonymizing network and + * belongs to a residential ISP. + * @param isTorExitNode Whether the IP address is a Tor exit node. + * @param network The network associated with the record. In particular, this is the largest + * network where all the fields besides IP address have the same value. + * @param ipRisk The IP risk of a model. */ -public class IpRiskResponse extends IpBaseResponse { +public record IpRiskResponse( + @JsonProperty("ip_address") + @MaxMindDbIpAddress + InetAddress ipAddress, - private final double ipRisk; + @JsonProperty("is_anonymous") + @MaxMindDbParameter(name = "is_anonymous", useDefault = true) + boolean isAnonymous, - /** - * Constructs an instance of {@code IpRiskResponse}. - * - * @param ipAddress the IP address being checked - * @param isAnonymous whether the IP address belongs to any sort of anonymous network - * @param isAnonymousVpn whether the IP address belongs to an anonymous VPN system - * @param isHostingProvider whether the IP address belongs to a hosting provider - * @param isPublicProxy whether the IP address belongs to a public proxy system - * @param isResidentialProxy whether the IP address belongs to a residential proxy system - * @param isTorExitNode whether the IP address is a Tor exit node - * @param network the network associated with the record - * @param ipRisk the IP risk of a model - */ - public IpRiskResponse( - @JsonProperty("ip_address") String ipAddress, - @JsonProperty("is_anonymous") boolean isAnonymous, - @JsonProperty("is_anonymous_vpn") boolean isAnonymousVpn, - @JsonProperty("is_hosting_provider") boolean isHostingProvider, - @JsonProperty("is_public_proxy") boolean isPublicProxy, - @JsonProperty("is_residential_proxy") boolean isResidentialProxy, - @JsonProperty("is_tor_exit_node") boolean isTorExitNode, - @JsonProperty("network") - @JsonDeserialize(using = NetworkDeserializer.class) Network network, - @JsonProperty("ip_risk") double ipRisk - ) { - super(ipAddress, isAnonymous, isAnonymousVpn, isHostingProvider, isPublicProxy, - isResidentialProxy, isTorExitNode, network); - this.ipRisk = ipRisk; - } + @JsonProperty("is_anonymous_vpn") + @MaxMindDbParameter(name = "is_anonymous_vpn", useDefault = true) + boolean isAnonymousVpn, - /** - * Constructs an instance of {@code IpRiskResponse}. - * - * @param ipAddress the IP address being checked - * @param isAnonymous whether the IP address belongs to any sort of anonymous network - * @param isAnonymousVpn whether the IP address belongs to an anonymous VPN system - * @param isHostingProvider whether the IP address belongs to a hosting provider - * @param isPublicProxy whether the IP address belongs to a public proxy system - * @param isResidentialProxy whether the IP address belongs to a residential proxy system - * @param isTorExitNode whether the IP address is a Tor exit node - * @param network the network associated with the record - * @param ipRisk the IP risk of a model - * - */ - @MaxMindDbConstructor - public IpRiskResponse( - @MaxMindDbParameter(name = "ip_address") String ipAddress, - @MaxMindDbParameter(name = "is_anonymous") Boolean isAnonymous, - @MaxMindDbParameter(name = "is_anonymous_vpn") Boolean isAnonymousVpn, - @MaxMindDbParameter(name = "is_hosting_provider") Boolean isHostingProvider, - @MaxMindDbParameter(name = "is_public_proxy") Boolean isPublicProxy, - @MaxMindDbParameter(name = "is_residential_proxy") Boolean isResidentialProxy, - @MaxMindDbParameter(name = "is_tor_exit_node") Boolean isTorExitNode, - @MaxMindDbParameter(name = "network") Network network, - @MaxMindDbParameter(name = "ip_risk") double ipRisk + @JsonProperty("is_hosting_provider") + @MaxMindDbParameter(name = "is_hosting_provider", useDefault = true) + boolean isHostingProvider, + + @JsonProperty("is_public_proxy") + @MaxMindDbParameter(name = "is_public_proxy", useDefault = true) + boolean isPublicProxy, - ) { - this( - ipAddress, - isAnonymous != null ? isAnonymous : false, - isAnonymousVpn != null ? isAnonymousVpn : false, - isHostingProvider != null ? isHostingProvider : false, - isPublicProxy != null ? isPublicProxy : false, - isResidentialProxy != null ? isResidentialProxy : false, - isTorExitNode != null ? isTorExitNode : false, - network, - ipRisk + @JsonProperty("is_residential_proxy") + @MaxMindDbParameter(name = "is_residential_proxy", useDefault = true) + boolean isResidentialProxy, - ); + @JsonProperty("is_tor_exit_node") + @MaxMindDbParameter(name = "is_tor_exit_node", useDefault = true) + boolean isTorExitNode, + + @JsonProperty("network") + @MaxMindDbNetwork + @JsonDeserialize(using = NetworkDeserializer.class) + Network network, + + @JsonProperty("ip_risk") + @MaxMindDbParameter(name = "ip_risk") + double ipRisk +) implements JsonSerializable { + + /** + * @return The IP address that the data in the model is for. + * @deprecated Use {@link #ipAddress()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("ip_address") + public String getIpAddress() { + return ipAddress().getHostAddress(); } /** - * Constructs an instance of {@code IpRiskResponse}. - * - * @param response The {@code IpRiskResponse} object to copy. - * @param ipAddress The IP address that the data in the model is for. - * @param network The network associated with the record. + * @return The network associated with the record. In particular, this is + * the largest network where all the fields besides IP address have the + * same value. + * @deprecated Use {@link #network()} instead. This method will be removed in 6.0.0. */ - public IpRiskResponse( - IpRiskResponse response, - String ipAddress, - Network network - ) { - this( - ipAddress, - response.isAnonymous(), - response.isAnonymousVpn(), - response.isHostingProvider(), - response.isPublicProxy(), - response.isResidentialProxy(), - response.isTorExitNode(), - network, - response.ipRisk - ); + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty + @JsonSerialize(using = ToStringSerializer.class) + public Network getNetwork() { + return network(); } /** * @return The IP risk of a model. + * @deprecated Use {@link #ipRisk()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("ip_risk") public double getIpRisk() { - return this.ipRisk; + return ipRisk(); } } diff --git a/src/main/java/com/maxmind/geoip2/model/IspResponse.java b/src/main/java/com/maxmind/geoip2/model/IspResponse.java index 3bc9f2d5..612816b4 100644 --- a/src/main/java/com/maxmind/geoip2/model/IspResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/IspResponse.java @@ -1,94 +1,112 @@ package com.maxmind.geoip2.model; -import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.maxmind.db.MaxMindDbConstructor; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.maxmind.db.MaxMindDbIpAddress; +import com.maxmind.db.MaxMindDbNetwork; import com.maxmind.db.MaxMindDbParameter; import com.maxmind.db.Network; +import com.maxmind.geoip2.JsonSerializable; import com.maxmind.geoip2.NetworkDeserializer; +import java.net.InetAddress; /** * This class provides the GeoIP2 ISP model. + * + * @param autonomousSystemNumber The autonomous system number associated with the IP address. + * @param autonomousSystemOrganization The organization associated with the registered autonomous + * system number for the IP address. + * @param ipAddress The IP address that the data in the model is for. + * @param isp The name of the ISP associated with the IP address. + * @param mobileCountryCode The + * mobile country code (MCC) associated with the IP address and ISP. + * This property is available from the City and Insights web services and + * the GeoIP2 Enterprise database. + * @param mobileNetworkCode The + * mobile network code (MNC) associated with the IP address and ISP. + * This property is available from the City and Insights web services and + * the GeoIP2 Enterprise database. + * @param organization The name of the organization associated with the IP address. + * @param network The network associated with the record. In particular, this is the largest + * network where all the fields besides IP address have the same value. */ -public class IspResponse extends AsnResponse { +public record IspResponse( + @JsonProperty("autonomous_system_number") + @MaxMindDbParameter(name = "autonomous_system_number") + Long autonomousSystemNumber, - private final String isp; - private final String organization; - private final String mobileCountryCode; - private final String mobileNetworkCode; + @JsonProperty("autonomous_system_organization") + @MaxMindDbParameter(name = "autonomous_system_organization") + String autonomousSystemOrganization, + + @JsonProperty("ip_address") + @MaxMindDbIpAddress + InetAddress ipAddress, + + @JsonProperty("isp") + @MaxMindDbParameter(name = "isp") + String isp, + + @JsonProperty("mobile_country_code") + @MaxMindDbParameter(name = "mobile_country_code") + String mobileCountryCode, + + @JsonProperty("mobile_network_code") + @MaxMindDbParameter(name = "mobile_network_code") + String mobileNetworkCode, + + @JsonProperty("organization") + @MaxMindDbParameter(name = "organization") + String organization, + + @JsonProperty("network") + @JsonDeserialize(using = NetworkDeserializer.class) + @MaxMindDbNetwork + Network network +) implements JsonSerializable { /** - * Constructs an instance of {@code IspResponse}. - * - * @param autonomousSystemNumber the autonomous system number associated with the IP - * address - * @param autonomousSystemOrganization the organization associated with the registered - * autonomous system number for the IP address - * @param ipAddress the IP address that the data in the model is for - * @param isp the name of the ISP associated with the IP address - * @param mobileCountryCode the mobile country code (MCC) associated with the IP - * @param mobileNetworkCode the mobile network code (MNC) associated with the IP - * @param organization the name of the organization associated with the IP - * address - * @param network the network associated with the record + * @return The autonomous system number associated with the IP address. + * @deprecated Use {@link #autonomousSystemNumber()} instead. This method will be removed + * in 6.0.0. */ - @MaxMindDbConstructor - public IspResponse( - @JsonProperty("autonomous_system_number") - @MaxMindDbParameter(name = "autonomous_system_number") Long autonomousSystemNumber, - @JsonProperty("autonomous_system_organization") - @MaxMindDbParameter(name = "autonomous_system_organization") - String autonomousSystemOrganization, - @JsonProperty("ip_address") - @MaxMindDbParameter(name = "ip_address") String ipAddress, - @JsonProperty("isp") @MaxMindDbParameter(name = "isp") String isp, - @JsonProperty("mobile_country_code") @MaxMindDbParameter(name = "mobile_country_code") - String mobileCountryCode, - @JsonProperty("mobile_network_code") @MaxMindDbParameter(name = "mobile_network_code") - String mobileNetworkCode, - @JsonProperty("organization") @MaxMindDbParameter(name = "organization") - String organization, - @JsonProperty("network") - @JsonDeserialize(using = NetworkDeserializer.class) @MaxMindDbParameter(name = "network") - Network network - ) { - super(autonomousSystemNumber, autonomousSystemOrganization, ipAddress, network); - this.isp = isp; - this.mobileCountryCode = mobileCountryCode; - this.mobileNetworkCode = mobileNetworkCode; - this.organization = organization; + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("autonomous_system_number") + public Long getAutonomousSystemNumber() { + return autonomousSystemNumber(); } /** - * Constructs an instance of {@code IspResponse}. - * - * @param response The {@code AsnResponse} object to copy. - * @param ipAddress The IP address that the data in the model is for. - * @param network The network associated with the record. + * @return The organization associated with the registered autonomous system + * number for the IP address + * @deprecated Use {@link #autonomousSystemOrganization()} instead. This method will be + * removed in 6.0.0. */ - public IspResponse( - IspResponse response, - String ipAddress, - Network network - ) { - this( - response.getAutonomousSystemNumber(), - response.getAutonomousSystemOrganization(), - ipAddress, - response.getIsp(), - response.getMobileCountryCode(), - response.getMobileNetworkCode(), - response.getOrganization(), - network - ); + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("autonomous_system_organization") + public String getAutonomousSystemOrganization() { + return autonomousSystemOrganization(); + } + + /** + * @return The IP address that the data in the model is for. + * @deprecated Use {@link #ipAddress()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("ip_address") + public String getIpAddress() { + return ipAddress().getHostAddress(); } /** * @return The name of the ISP associated with the IP address. + * @deprecated Use {@link #isp()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) public String getIsp() { - return this.isp; + return isp(); } /** @@ -96,10 +114,12 @@ public String getIsp() { * mobile country code (MCC) associated with the IP address and ISP. * This property is available from the City and Insights web services and * the GeoIP2 Enterprise database. + * @deprecated Use {@link #mobileCountryCode()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("mobile_country_code") public String getMobileCountryCode() { - return this.mobileCountryCode; + return mobileCountryCode(); } /** @@ -107,16 +127,33 @@ public String getMobileCountryCode() { * mobile network code (MNC) associated with the IP address and ISP. * This property is available from the City and Insights web services and * the GeoIP2 Enterprise database. + * @deprecated Use {@link #mobileNetworkCode()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("mobile_network_code") public String getMobileNetworkCode() { - return this.mobileNetworkCode; + return mobileNetworkCode(); } /** * @return The name of the organization associated with the IP address. + * @deprecated Use {@link #organization()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) public String getOrganization() { - return this.organization; + return organization(); + } + + /** + * @return The network associated with the record. In particular, this is + * the largest network where all the fields besides IP address have the + * same value. + * @deprecated Use {@link #network()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty + @JsonSerialize(using = ToStringSerializer.class) + public Network getNetwork() { + return network(); } } diff --git a/src/main/java/com/maxmind/geoip2/record/AbstractNamedRecord.java b/src/main/java/com/maxmind/geoip2/record/AbstractNamedRecord.java deleted file mode 100644 index c3f644ae..00000000 --- a/src/main/java/com/maxmind/geoip2/record/AbstractNamedRecord.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.maxmind.geoip2.record; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Abstract class for records with name maps. - */ -public abstract class AbstractNamedRecord extends AbstractRecord { - - private final Map names; - private final Long geoNameId; - private final List locales; - - AbstractNamedRecord() { - this(null, null, null); - } - - AbstractNamedRecord(List locales, Long geoNameId, Map names) { - this.names = names != null ? names : new HashMap<>(); - this.geoNameId = geoNameId; - this.locales = locales != null ? locales : new ArrayList<>(); - } - - /** - * @return The GeoName ID for the city. - */ - @JsonProperty("geoname_id") - public Long getGeoNameId() { - return this.geoNameId; - } - - /** - * @return The name of the city based on the locales list passed to the - * constructor. - */ - @JsonIgnore - public String getName() { - for (String lang : this.locales) { - if (this.names.containsKey(lang)) { - return this.names.get(lang); - } - } - return null; - } - - /** - * @return A {@link Map} from locale codes to the name in that locale. - */ - @JsonProperty("names") - public Map getNames() { - return new HashMap<>(this.names); - } -} diff --git a/src/main/java/com/maxmind/geoip2/record/City.java b/src/main/java/com/maxmind/geoip2/record/City.java index 98b5da9e..2ba14b2c 100644 --- a/src/main/java/com/maxmind/geoip2/record/City.java +++ b/src/main/java/com/maxmind/geoip2/record/City.java @@ -2,8 +2,8 @@ import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonProperty; -import com.maxmind.db.MaxMindDbConstructor; import com.maxmind.db.MaxMindDbParameter; +import com.maxmind.geoip2.NamedRecord; import java.util.List; import java.util.Map; @@ -13,38 +13,47 @@ *

*

* Do not use any of the city names as a database or map key. Use the value - * returned by {@link #getGeoNameId} instead. + * returned by {@link #geonameId()} instead. *

+ * + * @param locales The locales to use for retrieving localized names. + * @param confidence A value from 0-100 indicating MaxMind's confidence that the city + * is correct. This attribute is only available from the Insights + * web service and the GeoIP2 Enterprise database. + * @param geonameId The GeoName ID for the city. + * @param names A {@link Map} from locale codes to the name in that locale. */ -public final class City extends AbstractNamedRecord { +public record City( + @JacksonInject("locales") + @MaxMindDbParameter(name = "locales") + List locales, - private final Integer confidence; + @JsonProperty("confidence") + @MaxMindDbParameter(name = "confidence") + Integer confidence, + + @JsonProperty("geoname_id") + @MaxMindDbParameter(name = "geoname_id") + Long geonameId, + + @JsonProperty("names") + @MaxMindDbParameter(name = "names") + Map names +) implements NamedRecord { /** - * Constructs an instance of {@code City} with no data. + * Compact canonical constructor that ensures immutability and handles null values. */ - public City() { - this(null, null, null, null); + public City { + locales = locales != null ? List.copyOf(locales) : List.of(); + names = names != null ? Map.copyOf(names) : Map.of(); } /** - * Constructs an instance of {@code City} with the specified parameters. - * - * @param locales The locales to use. - * @param confidence A value from 0-100 indicating MaxMind's confidence that the - * city is correct. . - * @param geoNameId The GeoName ID for the city. - * @param names A map from locale codes to the city name in that locale. + * Constructs an instance of {@code City} with no data. */ - @MaxMindDbConstructor - public City( - @JacksonInject("locales") @MaxMindDbParameter(name = "locales") List locales, - @JsonProperty("confidence") @MaxMindDbParameter(name = "confidence") Integer confidence, - @JsonProperty("geoname_id") @MaxMindDbParameter(name = "geoname_id") Long geoNameId, - @JsonProperty("names") @MaxMindDbParameter(name = "names") Map names - ) { - super(locales, geoNameId, names); - this.confidence = confidence; + public City() { + this(null, null, null, null); } /** @@ -59,9 +68,9 @@ public City( ) { this( locales, - city.getConfidence(), - city.getGeoNameId(), - city.getNames() + city.confidence(), + city.geonameId(), + city.names() ); } @@ -69,8 +78,41 @@ public City( * @return A value from 0-100 indicating MaxMind's confidence that the city * is correct. This attribute is only available from the Insights * web service and the GeoIP2 Enterprise database. + * @deprecated Use {@link #confidence()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) public Integer getConfidence() { - return this.confidence; + return confidence(); + } + + /** + * @return The GeoName ID for the city. + * @deprecated Use {@link #geonameId()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("geoname_id") + public Long getGeoNameId() { + return geonameId(); + } + + /** + * @return The name of the city based on the locales list passed to the + * constructor. + * @deprecated Use {@link #name()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @com.fasterxml.jackson.annotation.JsonIgnore + public String getName() { + return name(); + } + + /** + * @return A {@link Map} from locale codes to the name in that locale. + * @deprecated Use {@link #names()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("names") + public Map getNames() { + return names(); } } diff --git a/src/main/java/com/maxmind/geoip2/record/Continent.java b/src/main/java/com/maxmind/geoip2/record/Continent.java index a103f3dc..968e100a 100644 --- a/src/main/java/com/maxmind/geoip2/record/Continent.java +++ b/src/main/java/com/maxmind/geoip2/record/Continent.java @@ -2,8 +2,8 @@ import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonProperty; -import com.maxmind.db.MaxMindDbConstructor; import com.maxmind.db.MaxMindDbParameter; +import com.maxmind.geoip2.NamedRecord; import java.util.List; import java.util.Map; @@ -13,38 +13,46 @@ *

*

* Do not use any of the continent names as a database or map key. Use the - * value returned by {@link #getGeoNameId} or {@link #getCode} instead. + * value returned by {@link #geonameId()} or {@link #code()} instead. *

+ * + * @param locales The locales to use for retrieving localized names. + * @param code A two character continent code like "NA" (North America) or "OC" + * (Oceania). + * @param geonameId The GeoName ID for the continent. + * @param names A {@link Map} from locale codes to the name in that locale. */ -public final class Continent extends AbstractNamedRecord { +public record Continent( + @JacksonInject("locales") + @MaxMindDbParameter(name = "locales") + List locales, - private final String code; + @JsonProperty("code") + @MaxMindDbParameter(name = "code") + String code, + + @JsonProperty("geoname_id") + @MaxMindDbParameter(name = "geoname_id") + Long geonameId, + + @JsonProperty("names") + @MaxMindDbParameter(name = "names") + Map names +) implements NamedRecord { /** - * Constructs an instance of {@code Continent} with no data. + * Compact canonical constructor that ensures immutability and handles null values. */ - public Continent() { - this(null, null, null, null); + public Continent { + locales = locales != null ? List.copyOf(locales) : List.of(); + names = names != null ? Map.copyOf(names) : Map.of(); } /** - * Constructs an instance of {@code Continent}. - * - * @param locales The locales to use. - * @param code A two character continent code like "NA" (North America) or - * "OC" (Oceania). - * @param geoNameId The GeoName ID for the continent. - * @param names A map from locale codes to the continent names. + * Constructs an instance of {@code Continent} with no data. */ - @MaxMindDbConstructor - public Continent( - @JacksonInject("locales") @MaxMindDbParameter(name = "locales") List locales, - @JsonProperty("code") @MaxMindDbParameter(name = "code") String code, - @JsonProperty("geoname_id") @MaxMindDbParameter(name = "geoname_id") Long geoNameId, - @JsonProperty("names") @MaxMindDbParameter(name = "names") Map names - ) { - super(locales, geoNameId, names); - this.code = code; + public Continent() { + this(null, null, null, null); } /** @@ -59,18 +67,49 @@ public Continent( ) { this( locales, - continent.getCode(), - continent.getGeoNameId(), - continent.getNames() + continent.code(), + continent.geonameId(), + continent.names() ); } /** * @return A two character continent code like "NA" (North America) or "OC" * (Oceania). + * @deprecated Use {@link #code()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) public String getCode() { - return this.code; + return code(); } + /** + * @return The GeoName ID for the continent. + * @deprecated Use {@link #geonameId()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("geoname_id") + public Long getGeoNameId() { + return geonameId(); + } + + /** + * @return The name of the continent based on the locales list. + * @deprecated Use {@link #name()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @com.fasterxml.jackson.annotation.JsonIgnore + public String getName() { + return name(); + } + + /** + * @return A {@link Map} from locale codes to the name in that locale. + * @deprecated Use {@link #names()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("names") + public Map getNames() { + return names(); + } } diff --git a/src/main/java/com/maxmind/geoip2/record/Country.java b/src/main/java/com/maxmind/geoip2/record/Country.java index 1db6309d..17e4e699 100644 --- a/src/main/java/com/maxmind/geoip2/record/Country.java +++ b/src/main/java/com/maxmind/geoip2/record/Country.java @@ -2,8 +2,8 @@ import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonProperty; -import com.maxmind.db.MaxMindDbConstructor; import com.maxmind.db.MaxMindDbParameter; +import com.maxmind.geoip2.NamedRecord; import java.util.List; import java.util.Map; @@ -13,50 +13,59 @@ *

*

* Do not use any of the country names as a database or map key. Use the value - * returned by {@link #getGeoNameId} or {@link #getIsoCode} instead. + * returned by {@link #geonameId()} or {@link #isoCode()} instead. *

+ * + * @param locales The locales to use for retrieving localized names. + * @param confidence A value from 0-100 indicating MaxMind's confidence that the + * country is correct. This attribute is only available from the + * Insights web service and the GeoIP2 Enterprise database. + * @param geonameId The GeoName ID for the country. + * @param isInEuropeanUnion This is true if the country is a member state of the + * European Union. + * @param isoCode The two-character ISO + * 3166-1 alpha code for the country. + * @param names A {@link Map} from locale codes to the name in that locale. */ -public class Country extends AbstractNamedRecord { +public record Country( + @JacksonInject("locales") + @MaxMindDbParameter(name = "locales") + List locales, - private final Integer confidence; - private final boolean isInEuropeanUnion; - private final String isoCode; + @JsonProperty("confidence") + @MaxMindDbParameter(name = "confidence") + Integer confidence, + + @JsonProperty("geoname_id") + @MaxMindDbParameter(name = "geoname_id") + Long geonameId, + + @JsonProperty("is_in_european_union") + @MaxMindDbParameter(name = "is_in_european_union", useDefault = true) + boolean isInEuropeanUnion, + + @JsonProperty("iso_code") + @MaxMindDbParameter(name = "iso_code") + String isoCode, + + @JsonProperty("names") + @MaxMindDbParameter(name = "names") + Map names +) implements NamedRecord { /** - * Constructs an instance of {@code Country} with no data. + * Compact canonical constructor that ensures immutability and handles null values. */ - public Country() { - this(null, null, null, false, null, null); + public Country { + locales = locales != null ? List.copyOf(locales) : List.of(); + names = names != null ? Map.copyOf(names) : Map.of(); } - /** - * Constructs an instance of {@code Country}. - * - * @param locales The locales to use. - * @param confidence This is a value from 0-100 indicating MaxMind's - * confidence that the country is correct. - * @param geoNameId This is a GeoName ID for the country. - * @param isInEuropeanUnion This is true if the country is a member state of - * the European Union. - * @param isoCode This is a string up to three characters long contain the - * country code. - * @param names This is a map from locale codes to the names for the country - * in that locale. + /** + * Constructs an instance of {@code Country} with no data. */ - @MaxMindDbConstructor - public Country( - @JacksonInject("locales") @MaxMindDbParameter(name = "locales") List locales, - @JsonProperty("confidence") @MaxMindDbParameter(name = "confidence") Integer confidence, - @JsonProperty("geoname_id") @MaxMindDbParameter(name = "geoname_id") Long geoNameId, - @JsonProperty("is_in_european_union") @MaxMindDbParameter(name = "is_in_european_union") - Boolean isInEuropeanUnion, - @JsonProperty("iso_code") @MaxMindDbParameter(name = "iso_code") String isoCode, - @JsonProperty("names") @MaxMindDbParameter(name = "names") Map names - ) { - super(locales, geoNameId, names); - this.confidence = confidence; - this.isInEuropeanUnion = isInEuropeanUnion != null ? isInEuropeanUnion : false; - this.isoCode = isoCode; + public Country() { + this(null, null, null, false, null, null); } /** @@ -71,11 +80,11 @@ public Country( ) { this( locales, - country.getConfidence(), - country.getGeoNameId(), + country.confidence(), + country.geonameId(), country.isInEuropeanUnion(), - country.getIsoCode(), - country.getNames() + country.isoCode(), + country.names() ); } @@ -83,27 +92,52 @@ public Country( * @return A value from 0-100 indicating MaxMind's confidence that the * country is correct. This attribute is only available from the * Insights web service and the GeoIP2 Enterprise database. + * @deprecated Use {@link #confidence()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) public Integer getConfidence() { - return this.confidence; - } - - /** - * @return This is true if the country is a member state of the European - * Union. - */ - @JsonProperty("is_in_european_union") - public boolean isInEuropeanUnion() { - return this.isInEuropeanUnion; + return confidence(); } /** * @return The two-character ISO * 3166-1 alpha code for the country. + * @deprecated Use {@link #isoCode()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("iso_code") public String getIsoCode() { - return this.isoCode; + return isoCode(); + } + + /** + * @return The GeoName ID for the country. + * @deprecated Use {@link #geonameId()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("geoname_id") + public Long getGeoNameId() { + return geonameId(); + } + + /** + * @return The name of the country based on the locales list. + * @deprecated Use {@link #name()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @com.fasterxml.jackson.annotation.JsonIgnore + public String getName() { + return name(); + } + + /** + * @return A {@link Map} from locale codes to the name in that locale. + * @deprecated Use {@link #names()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("names") + public Map getNames() { + return names(); } } diff --git a/src/main/java/com/maxmind/geoip2/record/Location.java b/src/main/java/com/maxmind/geoip2/record/Location.java index a1be28a2..846d3625 100644 --- a/src/main/java/com/maxmind/geoip2/record/Location.java +++ b/src/main/java/com/maxmind/geoip2/record/Location.java @@ -1,22 +1,60 @@ package com.maxmind.geoip2.record; import com.fasterxml.jackson.annotation.JsonProperty; -import com.maxmind.db.MaxMindDbConstructor; import com.maxmind.db.MaxMindDbParameter; +import com.maxmind.geoip2.JsonSerializable; /** *

* Contains data for the location record associated with an IP address. *

+ * + * @param accuracyRadius The approximate accuracy radius in kilometers around the + * latitude and longitude for the IP address. This is the radius + * where we have a 67% confidence that the device using the IP + * address resides within the circle centered at the latitude and + * longitude with the provided radius. + * @param averageIncome The average income in US dollars associated with the requested + * IP address. This attribute is only available from the Insights + * web service. + * @param latitude The approximate latitude of the location associated with the IP + * address. This value is not precise and should not be used to identify + * a particular address or household. + * @param longitude The approximate longitude of the location associated with the IP + * address. This value is not precise and should not be used to identify + * a particular address or household. + * @param populationDensity The estimated population per square kilometer associated with + * the IP address. This attribute is only available from the + * Insights web service. + * @param timeZone The time zone associated with location, as specified by the + * IANA Time Zone Database, + * e.g., "America/New_York". */ -public class Location extends AbstractRecord { +public record Location( + @JsonProperty("accuracy_radius") + @MaxMindDbParameter(name = "accuracy_radius") + Integer accuracyRadius, + + @JsonProperty("average_income") + @MaxMindDbParameter(name = "average_income") + Integer averageIncome, + + @JsonProperty("latitude") + @MaxMindDbParameter(name = "latitude") + Double latitude, + + @JsonProperty("longitude") + @MaxMindDbParameter(name = "longitude") + Double longitude, + + @JsonProperty("population_density") + @MaxMindDbParameter(name = "population_density") + Integer populationDensity, - private final Integer accuracyRadius; - private final Integer averageIncome; - private final Double latitude; - private final Double longitude; - private final Integer populationDensity; - private final String timeZone; + @JsonProperty("time_zone") + @MaxMindDbParameter(name = "time_zone") + String timeZone +) implements JsonSerializable { /** * Constructs a {@code Location} record with {@code null} values for all the fields. @@ -25,78 +63,40 @@ public Location() { this(null, null, null, null, null, null); } - /** - * Constructs an instance of {@code Location}. - * - * @param accuracyRadius The approximate accuracy radius in kilometers - * around the latitude and longitude for the IP address. This is the radius - * where we have a 67% confidence that the device using the IP address - * resides within the circle centered at the latitude and longitude with - * the provided radius. - * @param averageIncome The average income in US dollars associated with - * the requested IP address. This attribute is only available from the - * Insights web service. - * @param latitude The approximate latitude of the location associated - * with the IP address. This value is not precise and should not be used - * to identify a particular address or household. - * @param longitude The approximate longitude of the location associated - * with the IP address. This value is not precise and should not be used - * to identify a particular address or household. - * @param populationDensity The estimated population per square kilometer - * associated with the IP address. This attribute is only available from - * the Insights web service. - * @param timeZone The time zone associated with location, as specified by - * the IANA Time Zone - * Database, e.g., "America/New_York". - */ - @MaxMindDbConstructor - public Location( - @JsonProperty("accuracy_radius") @MaxMindDbParameter(name = "accuracy_radius") - Integer accuracyRadius, - @JsonProperty("average_income") @MaxMindDbParameter(name = "average_income") - Integer averageIncome, - @JsonProperty("latitude") @MaxMindDbParameter(name = "latitude") Double latitude, - @JsonProperty("longitude") @MaxMindDbParameter(name = "longitude") Double longitude, - @JsonProperty("population_density") @MaxMindDbParameter(name = "population_density") - Integer populationDensity, - @JsonProperty("time_zone") @MaxMindDbParameter(name = "time_zone") String timeZone - ) { - this.accuracyRadius = accuracyRadius; - this.averageIncome = averageIncome; - this.latitude = latitude; - this.longitude = longitude; - this.populationDensity = populationDensity; - this.timeZone = timeZone; - } - /** * @return The average income in US dollars associated with the requested * IP address. This attribute is only available from the Insights web * service. + * @deprecated Use {@link #averageIncome()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("average_income") public Integer getAverageIncome() { - return this.averageIncome; + return averageIncome(); } /** * @return The estimated population per square kilometer associated with the * IP address. This attribute is only available from the Insights web * service. + * @deprecated Use {@link #populationDensity()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("population_density") public Integer getPopulationDensity() { - return this.populationDensity; + return populationDensity(); } /** * @return The time zone associated with location, as specified by the IANA Time Zone * Database, e.g., "America/New_York". + * @deprecated Use {@link #timeZone()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("time_zone") public String getTimeZone() { - return this.timeZone; + return timeZone(); } /** @@ -105,28 +105,33 @@ public String getTimeZone() { * have a 67% confidence that the device using the IP address resides * within the circle centered at the latitude and longitude with the * provided radius. + * @deprecated Use {@link #accuracyRadius()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("accuracy_radius") public Integer getAccuracyRadius() { - return this.accuracyRadius; + return accuracyRadius(); } - /** * @return The approximate latitude of the location associated with the * IP address. This value is not precise and should not be used to * identify a particular address or household. + * @deprecated Use {@link #latitude()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) public Double getLatitude() { - return this.latitude; + return latitude(); } /** * @return The approximate longitude of the location associated with the * IP address. This value is not precise and should not be used to * identify a particular address or household. + * @deprecated Use {@link #longitude()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) public Double getLongitude() { - return this.longitude; + return longitude(); } } diff --git a/src/main/java/com/maxmind/geoip2/record/MaxMind.java b/src/main/java/com/maxmind/geoip2/record/MaxMind.java index 6bdd9ef6..a9380b89 100644 --- a/src/main/java/com/maxmind/geoip2/record/MaxMind.java +++ b/src/main/java/com/maxmind/geoip2/record/MaxMind.java @@ -1,17 +1,22 @@ package com.maxmind.geoip2.record; import com.fasterxml.jackson.annotation.JsonProperty; -import com.maxmind.db.MaxMindDbConstructor; import com.maxmind.db.MaxMindDbParameter; +import com.maxmind.geoip2.JsonSerializable; /** *

* Contains data related to your MaxMind account. *

+ * + * @param queriesRemaining The number of remaining queries in your account for the current + * web service. This returns {@code null} when called on a database. */ -public final class MaxMind extends AbstractRecord { - - private final Integer queriesRemaining; +public record MaxMind( + @JsonProperty("queries_remaining") + @MaxMindDbParameter(name = "queries_remaining") + Integer queriesRemaining +) implements JsonSerializable { /** * Constructs a {@code MaxMind} record. @@ -21,24 +26,13 @@ public MaxMind() { } /** - * Constructs a {@code MaxMind} record. - * - * @param queriesRemaining The number of remaining queries in the current web service call. - * This returns {@code null} when called on a database. - */ - @MaxMindDbConstructor - public MaxMind( - @JsonProperty("queries_remaining") @MaxMindDbParameter(name = "queries_remaining") - Integer queriesRemaining) { - this.queriesRemaining = queriesRemaining; - } - - /** - * @return The number of remaining queried in your account for the current + * @return The number of remaining queries in your account for the current * web service. This returns {@code null} when called on a database. + * @deprecated Use {@link #queriesRemaining()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("queries_remaining") public Integer getQueriesRemaining() { - return this.queriesRemaining; + return queriesRemaining(); } } diff --git a/src/main/java/com/maxmind/geoip2/record/Postal.java b/src/main/java/com/maxmind/geoip2/record/Postal.java index 05435116..be7680a5 100644 --- a/src/main/java/com/maxmind/geoip2/record/Postal.java +++ b/src/main/java/com/maxmind/geoip2/record/Postal.java @@ -1,18 +1,30 @@ package com.maxmind.geoip2.record; import com.fasterxml.jackson.annotation.JsonProperty; -import com.maxmind.db.MaxMindDbConstructor; import com.maxmind.db.MaxMindDbParameter; +import com.maxmind.geoip2.JsonSerializable; /** *

* Contains data for the postal record associated with an IP address. *

+ * + * @param code The postal code of the location. Postal codes are not available for all + * countries. In some countries, this will only contain part of the postal + * code. + * @param confidence A value from 0-100 indicating MaxMind's confidence that the postal + * code is correct. This attribute is only available from the Insights + * web service and the GeoIP2 Enterprise database. */ -public final class Postal extends AbstractRecord { +public record Postal( + @JsonProperty("code") + @MaxMindDbParameter(name = "code") + String code, - private final String code; - private final Integer confidence; + @JsonProperty("confidence") + @MaxMindDbParameter(name = "confidence") + Integer confidence +) implements JsonSerializable { /** * Constructs a {@code Postal} record. @@ -21,40 +33,25 @@ public Postal() { this(null, null); } - /** - * Constructs an instance of {@code Postal}. - * - * @param code The postal code of the location. Postal codes are not available - * for all countries. In some countries, this will only contain part - * of the postal code. - * @param confidence A value from 0-100 indicating MaxMind's confidence that the - * postal code is correct. This attribute is only available from the - * Insights web service and the GeoIP2 Enterprise database. - */ - @MaxMindDbConstructor - public Postal( - @JsonProperty("code") @MaxMindDbParameter(name = "code") String code, - @JsonProperty("confidence") @MaxMindDbParameter(name = "confidence") Integer confidence - ) { - this.code = code; - this.confidence = confidence; - } - /** * @return The postal code of the location. Postal codes are not available * for all countries. In some countries, this will only contain part * of the postal code. + * @deprecated Use {@link #code()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) public String getCode() { - return this.code; + return code(); } /** * @return A value from 0-100 indicating MaxMind's confidence that the * postal code is correct. This attribute is only available from the * Insights web service and the GeoIP2 Enterprise database. + * @deprecated Use {@link #confidence()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) public Integer getConfidence() { - return this.confidence; + return confidence(); } } diff --git a/src/main/java/com/maxmind/geoip2/record/RepresentedCountry.java b/src/main/java/com/maxmind/geoip2/record/RepresentedCountry.java index 61c1a187..be9c0234 100644 --- a/src/main/java/com/maxmind/geoip2/record/RepresentedCountry.java +++ b/src/main/java/com/maxmind/geoip2/record/RepresentedCountry.java @@ -2,8 +2,8 @@ import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonProperty; -import com.maxmind.db.MaxMindDbConstructor; import com.maxmind.db.MaxMindDbParameter; +import com.maxmind.geoip2.NamedRecord; import java.util.List; import java.util.Map; @@ -18,53 +18,69 @@ *

*

* Do not use any of the country names as a database or map key. Use the value - * returned by {@link #getGeoNameId} or {@link #getIsoCode} instead. + * returned by {@link #geonameId()} or {@link #isoCode()} instead. *

+ * + * @param locales The locales to use for retrieving localized names. + * @param confidence A value from 0-100 indicating MaxMind's confidence that the + * country is correct. This attribute is only available from the + * Insights web service and the GeoIP2 Enterprise database. + * @param geonameId The GeoName ID for the country. + * @param isInEuropeanUnion This is true if the country is a member state of the + * European Union. + * @param isoCode The two-character ISO + * 3166-1 alpha code for the country. + * @param names A {@link Map} from locale codes to the name in that locale. + * @param type A string indicating the type of entity that is representing the + * country. Currently, we only return {@code military} but this could + * expand to include other types in the future. */ -public final class RepresentedCountry extends Country { +public record RepresentedCountry( + @JacksonInject("locales") + @MaxMindDbParameter(name = "locales") + List locales, - private final String type; + @JsonProperty("confidence") + @MaxMindDbParameter(name = "confidence") + Integer confidence, + + @JsonProperty("geoname_id") + @MaxMindDbParameter(name = "geoname_id") + Long geonameId, + + @JsonProperty("is_in_european_union") + @MaxMindDbParameter(name = "is_in_european_union", useDefault = true) + boolean isInEuropeanUnion, + + @JsonProperty("iso_code") + @MaxMindDbParameter(name = "iso_code") + String isoCode, + + @JsonProperty("names") + @MaxMindDbParameter(name = "names") + Map names, + + @JsonProperty("type") + @MaxMindDbParameter(name = "type") + String type +) implements NamedRecord { /** - * Constructs an instance of {@code RepresentedCountry} with no data. + * Compact canonical constructor that ensures immutability and handles null values. */ - public RepresentedCountry() { - this(null, null, null, false, null, null, null); + public RepresentedCountry { + locales = locales != null ? List.copyOf(locales) : List.of(); + names = names != null ? Map.copyOf(names) : Map.of(); } /** - * Constructs an instance of {@code RepresentedCountry}. - * - * @param locales The locales to use. - * @param confidence This is a value from 0-100 indicating MaxMind's - * confidence that the country is correct. - * @param geoNameId This is a GeoName ID for the country. - * @param isInEuropeanUnion This is true if the country is a member state of - * the European Union. - * @param isoCode This is a string up to three characters long contain the - * country code. - * @param names This is a map from locale codes to the names for the country - * in that locale. - * @param type This is a string indicating the type of entity that is - * representing the country. + * Constructs an instance of {@code RepresentedCountry} with no data. */ - @MaxMindDbConstructor - public RepresentedCountry( - @JacksonInject("locales") @MaxMindDbParameter(name = "locales") List locales, - @JsonProperty("confidence") @MaxMindDbParameter(name = "confidence") Integer confidence, - @JsonProperty("geoname_id") @MaxMindDbParameter(name = "geoname_id") Long geoNameId, - @JsonProperty("is_in_european_union") @MaxMindDbParameter(name = "is_in_european_union") - Boolean isInEuropeanUnion, - @JsonProperty("iso_code") @MaxMindDbParameter(name = "iso_code") String isoCode, - @JsonProperty("names") @MaxMindDbParameter(name = "names") Map names, - @JsonProperty("type") @MaxMindDbParameter(name = "type") String type - ) { - super(locales, confidence, geoNameId, isInEuropeanUnion, isoCode, - names); - this.type = type; + public RepresentedCountry() { + this(null, null, null, false, null, null, null); } - /** + /** * Constructs an instance of {@code RepresentedCountry}. * * @param country The {@code RepresentedCountry} object to copy. @@ -76,12 +92,12 @@ public RepresentedCountry( ) { this( locales, - country.getConfidence(), - country.getGeoNameId(), + country.confidence(), + country.geonameId(), country.isInEuropeanUnion(), - country.getIsoCode(), - country.getNames(), - country.getType() + country.isoCode(), + country.names(), + country.type() ); } @@ -89,9 +105,63 @@ public RepresentedCountry( * @return A string indicating the type of entity that is representing the * country. Currently, we only return {@code military} but this could * expand to include other types in the future. + * @deprecated Use {@link #type()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) public String getType() { - return this.type; + return type(); + } + + /** + * @return A value from 0-100 indicating MaxMind's confidence that the + * country is correct. This attribute is only available from the + * Insights web service and the GeoIP2 Enterprise database. + * @deprecated Use {@link #confidence()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + public Integer getConfidence() { + return confidence(); + } + + /** + * @return The two-character ISO + * 3166-1 alpha code for the country. + * @deprecated Use {@link #isoCode()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("iso_code") + public String getIsoCode() { + return isoCode(); + } + + /** + * @return The GeoName ID for the country. + * @deprecated Use {@link #geonameId()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("geoname_id") + public Long getGeoNameId() { + return geonameId(); } + /** + * @return The name of the country based on the locales list. + * @deprecated Use {@link #name()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @com.fasterxml.jackson.annotation.JsonIgnore + public String getName() { + return name(); + } + + /** + * @return A {@link Map} from locale codes to the name in that locale. + * @deprecated Use {@link #names()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("names") + public Map getNames() { + return names(); + } } diff --git a/src/main/java/com/maxmind/geoip2/record/Subdivision.java b/src/main/java/com/maxmind/geoip2/record/Subdivision.java index 3a1cd4af..460fc6f1 100644 --- a/src/main/java/com/maxmind/geoip2/record/Subdivision.java +++ b/src/main/java/com/maxmind/geoip2/record/Subdivision.java @@ -2,8 +2,8 @@ import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonProperty; -import com.maxmind.db.MaxMindDbConstructor; import com.maxmind.db.MaxMindDbParameter; +import com.maxmind.geoip2.NamedRecord; import java.util.List; import java.util.Map; @@ -13,13 +13,48 @@ *

*

* Do not use any of the subdivision names as a database or map key. Use the - * value returned by {@link #getGeoNameId} or {@link #getIsoCode} instead. + * value returned by {@link #geonameId()} or {@link #isoCode()} instead. *

+ * + * @param locales The locales to use for retrieving localized names. + * @param confidence A value from 0-100 indicating MaxMind's confidence that the + * subdivision is correct. This attribute is only available from + * the Insights web service and the GeoIP2 Enterprise database. + * @param geonameId The GeoName ID for the subdivision. + * @param isoCode A string up to three characters long containing the subdivision + * portion of the ISO + * 3166-2 code. + * @param names A {@link Map} from locale codes to the name in that locale. */ -public final class Subdivision extends AbstractNamedRecord { +public record Subdivision( + @JacksonInject("locales") + @MaxMindDbParameter(name = "locales") + List locales, - private final Integer confidence; - private final String isoCode; + @JsonProperty("confidence") + @MaxMindDbParameter(name = "confidence") + Integer confidence, + + @JsonProperty("geoname_id") + @MaxMindDbParameter(name = "geoname_id") + Long geonameId, + + @JsonProperty("iso_code") + @MaxMindDbParameter(name = "iso_code") + String isoCode, + + @JsonProperty("names") + @MaxMindDbParameter(name = "names") + Map names +) implements NamedRecord { + + /** + * Compact canonical constructor that ensures immutability and handles null values. + */ + public Subdivision { + locales = locales != null ? List.copyOf(locales) : List.of(); + names = names != null ? Map.copyOf(names) : Map.of(); + } /** * Constructs a {@code Subdivision} record. @@ -28,29 +63,6 @@ public Subdivision() { this(null, null, null, null, null); } - /** - * Constructs an instance of {@code Subdivision}. - * - * @param locales The locales to use. - * @param confidence This is a value from 0-100 indicating MaxMind's - * confidence that the subdivision is correct. - * @param geoNameId This is a GeoName ID for the subdivision. - * @param isoCode This is a string up to three characters long contain the subdivision code. - * @param names This is a map from locale codes to the names for the subdivision in that locale. - */ - @MaxMindDbConstructor - public Subdivision( - @JacksonInject("locales") @MaxMindDbParameter(name = "locales") List locales, - @JsonProperty("confidence") @MaxMindDbParameter(name = "confidence") Integer confidence, - @JsonProperty("geoname_id") @MaxMindDbParameter(name = "geoname_id") Long geoNameId, - @JsonProperty("iso_code") @MaxMindDbParameter(name = "iso_code") String isoCode, - @JsonProperty("names") @MaxMindDbParameter(name = "names") Map names - ) { - super(locales, geoNameId, names); - this.confidence = confidence; - this.isoCode = isoCode; - } - /** * Constructs an instance of {@code Subdivision} with the specified parameters. * @@ -63,31 +75,65 @@ public Subdivision( ) { this( locales, - subdivision.getConfidence(), - subdivision.getGeoNameId(), - subdivision.getIsoCode(), - subdivision.getNames() + subdivision.confidence(), + subdivision.geonameId(), + subdivision.isoCode(), + subdivision.names() ); } /** - * @return This is a value from 0-100 indicating MaxMind's confidence that + * @return A value from 0-100 indicating MaxMind's confidence that * the subdivision is correct. This attribute is only available from * the Insights web service and the GeoIP2 Enterprise database. + * @deprecated Use {@link #confidence()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("confidence") public Integer getConfidence() { - return this.confidence; + return confidence(); } /** - * @return This is a string up to three characters long contain the + * @return A string up to three characters long containing the * subdivision portion of the ISO - * 3166-2code. + * 3166-2 code. + * @deprecated Use {@link #isoCode()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("iso_code") public String getIsoCode() { - return this.isoCode; + return isoCode(); + } + + /** + * @return The GeoName ID for the subdivision. + * @deprecated Use {@link #geonameId()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("geoname_id") + public Long getGeoNameId() { + return geonameId(); + } + + /** + * @return The name of the subdivision based on the locales list. + * @deprecated Use {@link #name()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @com.fasterxml.jackson.annotation.JsonIgnore + public String getName() { + return name(); + } + + /** + * @return A {@link Map} from locale codes to the name in that locale. + * @deprecated Use {@link #names()} instead. This method will be removed in 6.0.0. + */ + @Deprecated(since = "5.0.0", forRemoval = true) + @JsonProperty("names") + public Map getNames() { + return names(); } } diff --git a/src/main/java/com/maxmind/geoip2/record/Traits.java b/src/main/java/com/maxmind/geoip2/record/Traits.java index 0330fcdf..2540b9d0 100644 --- a/src/main/java/com/maxmind/geoip2/record/Traits.java +++ b/src/main/java/com/maxmind/geoip2/record/Traits.java @@ -1,248 +1,174 @@ package com.maxmind.geoip2.record; -import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; -import com.maxmind.db.MaxMindDbConstructor; +import com.maxmind.db.MaxMindDbIpAddress; +import com.maxmind.db.MaxMindDbNetwork; import com.maxmind.db.MaxMindDbParameter; import com.maxmind.db.Network; +import com.maxmind.geoip2.JsonSerializable; import com.maxmind.geoip2.NetworkDeserializer; import com.maxmind.geoip2.model.ConnectionTypeResponse.ConnectionType; +import java.net.InetAddress; /** * Contains data for the traits record associated with an IP address. + * + * @param autonomousSystemNumber The autonomous system number associated with the IP address. + * This is only available from the City Plus and Insights web + * services and the Enterprise database. + * @param autonomousSystemOrganization The organization associated with the registered autonomous system number for the IP address. This is + * only available from the City Plus and Insights web services + * and the Enterprise database. + * @param connectionType The connection type of the IP address. This is only available from the + * City Plus and Insights web services and the Enterprise database. + * @param domain The second level domain associated with the IP address. This will be something + * like "example.com" or "example.co.uk", not "foo.example.com". This is only + * available from the City Plus and Insights web services and the Enterprise + * database. + * @param ipAddress The IP address that the data in the model is for. If you performed a "me" + * lookup against the web service, this will be the externally routable IP + * address for the system the code is running on. If the system is behind a + * NAT, this may differ from the IP address locally assigned to it. + * @param isAnonymous This is true if the IP address belongs to any sort of anonymous network. + * @param isAnonymousVpn This is true if the IP address belongs to an anonymous VPN system. + * @param isAnycast This is true if the IP address is an anycast address. + * @param isHostingProvider This is true if the IP address belongs to a hosting provider. + * @param isLegitimateProxy This is true if the IP address belongs to a legitimate proxy. + * @param isPublicProxy This is true if the IP address belongs to a public proxy. + * @param isResidentialProxy This is true if the IP address is on a suspected anonymizing network + * and belongs to a residential ISP. + * @param isTorExitNode This is true if the IP address is a Tor exit node. + * @param isp The name of the ISP associated with the IP address. This is only available from + * the City Plus and Insights web services and the Enterprise database. + * @param mobileCountryCode The + * mobile country code (MCC) associated with the IP address and ISP. + * This is available from the City Plus and Insights web services and + * the Enterprise database. + * @param mobileNetworkCode The + * mobile network code (MNC) associated with the IP address and ISP. + * This is available from the City Plus and Insights web services and + * the Enterprise database. + * @param network The network associated with the record. In particular, this is the largest + * network where all the fields besides IP address have the same value. + * @param organization The name of the organization associated with the IP address. This is only + * available from the City Plus and Insights web services and the Enterprise + * database. + * @param userType The user type associated with the IP address. This can be one of the following + * values: business, cafe, cellular, college, consumer_privacy_network, + * content_delivery_network, dialup, government, hosting, library, military, + * residential, router, school, search_engine_spider, traveler. This is only + * available from the Insights web service and the Enterprise database. + * @param userCount The estimated number of users sharing the IP address/network during the past + * 24 hours. For IPv4, the count is for the individual IP address. For IPv6, the + * count is for the /64 network. This is only available from the Insights web + * service. + * @param staticIpScore The static IP score of the IP address. This is an indicator of how static + * or dynamic an IP address is. This is only available from the Insights web + * service. */ -public final class Traits extends AbstractRecord { - - private final Long autonomousSystemNumber; - private final String autonomousSystemOrganization; - private final ConnectionType connectionType; - private final String domain; - private final String ipAddress; - private final boolean isAnonymous; - private final boolean isAnonymousVpn; - private final boolean isAnycast; - private final boolean isHostingProvider; - private final boolean isLegitimateProxy; - private final boolean isPublicProxy; - private final boolean isResidentialProxy; - private final boolean isTorExitNode; - private final String isp; - private final String mobileCountryCode; - private final String mobileNetworkCode; - private final Network network; - private final String organization; - private final String userType; - private final Integer userCount; - private final Double staticIpScore; +public record Traits( + @JsonProperty("autonomous_system_number") + @MaxMindDbParameter(name = "autonomous_system_number") + Long autonomousSystemNumber, - /** - * Constructs an instance of {@code Traits}. - */ - public Traits() { - this(null, null, null, null, - null, false, false, false, false, - false, false, false, false, null, - null, null, null, null, null, null, null); - } + @JsonProperty("autonomous_system_organization") + @MaxMindDbParameter(name = "autonomous_system_organization") + String autonomousSystemOrganization, - /** - * Constructs an instance of {@code Traits}. - * - * @param ipAddress the IP address - * @param network the network - */ - public Traits(String ipAddress, Network network) { - this(null, null, null, null, - ipAddress, false, false, false, false, - false, false, false, false, null, - null, null, network, null, null, null, null); - } + @JsonProperty("connection_type") + @MaxMindDbParameter(name = "connection_type") + ConnectionType connectionType, - /** - * Constructs an instance of {@code Traits}. - * - * @param autonomousSystemNumber the autonomous system number - * @param autonomousSystemOrganization the autonomous system organization - * @param connectionType the connection type - * @param domain the domain - * @param ipAddress the IP address - * @param isAnonymous the anonymous flag - * @param isAnonymousVpn the anonymous VPN flag - * @param isAnycast the anycast flag - * @param isHostingProvider the hosting provider flag - * @param isLegitimateProxy the legitimate proxy flag - * @param isPublicProxy the public proxy flag - * @param isResidentialProxy the residential proxy flag - * @param isTorExitNode the Tor exit node flag - * @param isp the ISP - * @param mobileCountryCode the mobile country code - * @param mobileNetworkCode the mobile network code - * @param network the network - * @param organization the organization - * @param userType the user type - * @param userCount the user count - * @param staticIpScore the static IP score - */ - public Traits( - @JsonProperty("autonomous_system_number") Long autonomousSystemNumber, - @JsonProperty("autonomous_system_organization") String autonomousSystemOrganization, - @JsonProperty("connection_type") ConnectionType connectionType, - @JsonProperty("domain") String domain, - @JsonProperty("ip_address") String ipAddress, - @JsonProperty("is_anonymous") boolean isAnonymous, - @JsonProperty("is_anonymous_vpn") boolean isAnonymousVpn, - @JsonProperty("is_anycast") boolean isAnycast, - @JsonProperty("is_hosting_provider") boolean isHostingProvider, - @JsonProperty("is_legitimate_proxy") boolean isLegitimateProxy, - @JsonProperty("is_public_proxy") boolean isPublicProxy, - @JsonProperty("is_residential_proxy") boolean isResidentialProxy, - @JsonProperty("is_tor_exit_node") boolean isTorExitNode, - @JsonProperty("isp") String isp, - @JsonProperty("mobile_country_code") String mobileCountryCode, - @JsonProperty("mobile_network_code") String mobileNetworkCode, - @JsonProperty("network") - @JsonDeserialize(using = NetworkDeserializer.class) Network network, - @JsonProperty("organization") String organization, - @JsonProperty("user_type") String userType, - @JsonProperty("user_count") Integer userCount, - @JsonProperty("static_ip_score") Double staticIpScore - ) { - this.autonomousSystemNumber = autonomousSystemNumber; - this.autonomousSystemOrganization = autonomousSystemOrganization; - this.connectionType = connectionType; - this.domain = domain; - this.ipAddress = ipAddress; - this.isAnonymous = isAnonymous; - this.isAnonymousVpn = isAnonymousVpn; - this.isAnycast = isAnycast; - this.isHostingProvider = isHostingProvider; - this.isLegitimateProxy = isLegitimateProxy; - this.isPublicProxy = isPublicProxy; - this.isResidentialProxy = isResidentialProxy; - this.isTorExitNode = isTorExitNode; - this.isp = isp; - this.mobileCountryCode = mobileCountryCode; - this.mobileNetworkCode = mobileNetworkCode; - this.network = network; - this.organization = organization; - this.userType = userType; - this.userCount = userCount; - this.staticIpScore = staticIpScore; - } + @JsonProperty("domain") + @MaxMindDbParameter(name = "domain") + String domain, - /** - * Constructs an instance of {@code Traits}. - * - * @param autonomousSystemNumber the autonomous system number - * @param autonomousSystemOrganization the autonomous system organization - * @param connectionType the connection type - * @param domain the domain - * @param ipAddress the IP address - * @param isAnonymous the anonymous flag - * @param isAnonymousVpn the anonymous VPN flag - * @param isAnycast the anycast flag - * @param isHostingProvider the hosting provider flag - * @param isLegitimateProxy the legitimate proxy flag - * @param isPublicProxy the public proxy flag - * @param isResidentialProxy the residential proxy flag - * @param isTorExitNode the Tor exit node flag - * @param isp the ISP - * @param mobileCountryCode the mobile country code - * @param mobileNetworkCode the mobile network code - * @param network the network - * @param organization the organization - * @param userType the user type - * @param userCount the user count - * @param staticIpScore the static IP score - */ - @MaxMindDbConstructor - public Traits( - @MaxMindDbParameter(name = "autonomous_system_number") Long autonomousSystemNumber, - @MaxMindDbParameter(name = "autonomous_system_organization") - String autonomousSystemOrganization, - @MaxMindDbParameter(name = "connection_type") String connectionType, - @MaxMindDbParameter(name = "domain") String domain, - @MaxMindDbParameter(name = "ip_address") String ipAddress, - @MaxMindDbParameter(name = "is_anonymous") Boolean isAnonymous, - @MaxMindDbParameter(name = "is_anonymous_vpn") Boolean isAnonymousVpn, - @MaxMindDbParameter(name = "is_anycast") Boolean isAnycast, - @MaxMindDbParameter(name = "is_hosting_provider") Boolean isHostingProvider, - @MaxMindDbParameter(name = "is_legitimate_proxy") Boolean isLegitimateProxy, - @MaxMindDbParameter(name = "is_public_proxy") Boolean isPublicProxy, - @MaxMindDbParameter(name = "is_residential_proxy") Boolean isResidentialProxy, - @MaxMindDbParameter(name = "is_tor_exit_node") Boolean isTorExitNode, - @MaxMindDbParameter(name = "isp") String isp, - @MaxMindDbParameter(name = "mobile_country_code") String mobileCountryCode, - @MaxMindDbParameter(name = "mobile_network_code") String mobileNetworkCode, - @MaxMindDbParameter(name = "network") Network network, - @MaxMindDbParameter(name = "organization") String organization, - @MaxMindDbParameter(name = "user_type") String userType, - @MaxMindDbParameter(name = "user_count") Integer userCount, - @MaxMindDbParameter(name = "static_ip_score") Double staticIpScore - ) { - this.autonomousSystemNumber = autonomousSystemNumber; - this.autonomousSystemOrganization = autonomousSystemOrganization; - this.connectionType = ConnectionType.fromString(connectionType); - this.domain = domain; - this.ipAddress = ipAddress; - this.isAnonymous = isAnonymous != null ? isAnonymous : false; - this.isAnonymousVpn = isAnonymousVpn != null ? isAnonymousVpn : false; - this.isAnycast = isAnycast != null ? isAnycast : false; - this.isHostingProvider = isHostingProvider != null ? isHostingProvider : false; - this.isLegitimateProxy = isLegitimateProxy != null ? isLegitimateProxy : false; - this.isPublicProxy = isPublicProxy != null ? isPublicProxy : false; - this.isResidentialProxy = isResidentialProxy != null ? isResidentialProxy : false; - this.isTorExitNode = isTorExitNode != null ? isTorExitNode : false; - this.isp = isp; - this.mobileCountryCode = mobileCountryCode; - this.mobileNetworkCode = mobileNetworkCode; - this.network = network; - this.organization = organization; - this.userType = userType; - this.userCount = userCount; - this.staticIpScore = staticIpScore; - } + @JsonProperty("ip_address") + @MaxMindDbIpAddress + InetAddress ipAddress, + @JsonProperty("is_anonymous") + @MaxMindDbParameter(name = "is_anonymous", useDefault = true) + boolean isAnonymous, + @JsonProperty("is_anonymous_vpn") + @MaxMindDbParameter(name = "is_anonymous_vpn", useDefault = true) + boolean isAnonymousVpn, + + @JsonProperty("is_anycast") + @MaxMindDbParameter(name = "is_anycast", useDefault = true) + boolean isAnycast, + + @JsonProperty("is_hosting_provider") + @MaxMindDbParameter(name = "is_hosting_provider", useDefault = true) + boolean isHostingProvider, + + @JsonProperty("is_legitimate_proxy") + @MaxMindDbParameter(name = "is_legitimate_proxy", useDefault = true) + boolean isLegitimateProxy, + + @JsonProperty("is_public_proxy") + @MaxMindDbParameter(name = "is_public_proxy", useDefault = true) + boolean isPublicProxy, + + @JsonProperty("is_residential_proxy") + @MaxMindDbParameter(name = "is_residential_proxy", useDefault = true) + boolean isResidentialProxy, + + @JsonProperty("is_tor_exit_node") + @MaxMindDbParameter(name = "is_tor_exit_node", useDefault = true) + boolean isTorExitNode, + + @JsonProperty("isp") + @MaxMindDbParameter(name = "isp") + String isp, + + @JsonProperty("mobile_country_code") + @MaxMindDbParameter(name = "mobile_country_code") + String mobileCountryCode, + + @JsonProperty("mobile_network_code") + @MaxMindDbParameter(name = "mobile_network_code") + String mobileNetworkCode, + + @JsonProperty("network") + @JsonDeserialize(using = NetworkDeserializer.class) + @JsonSerialize(using = ToStringSerializer.class) + @MaxMindDbNetwork + Network network, + + @JsonProperty("organization") + @MaxMindDbParameter(name = "organization") + String organization, + + @JsonProperty("user_type") + @MaxMindDbParameter(name = "user_type") + String userType, + + @JsonProperty("user_count") + @MaxMindDbParameter(name = "user_count") + Integer userCount, + + @JsonProperty("static_ip_score") + @MaxMindDbParameter(name = "static_ip_score") + Double staticIpScore +) implements JsonSerializable { /** - * Constructs an instance of {@code Traits}. - * - * @param traits the traits - * @param ipAddress the IP address - * @param network the network + * Constructs an instance of {@code Traits}. */ - public Traits( - Traits traits, - String ipAddress, - Network network - ) { - this( - traits.getAutonomousSystemNumber(), - traits.getAutonomousSystemOrganization(), - traits.getConnectionType(), - traits.getDomain(), - ipAddress, - traits.isAnonymous(), - traits.isAnonymousVpn(), - traits.isAnycast(), - traits.isHostingProvider(), - traits.isLegitimateProxy(), - traits.isPublicProxy(), - traits.isResidentialProxy(), - traits.isTorExitNode(), - traits.getIsp(), - traits.getMobileCountryCode(), - traits.getMobileNetworkCode(), - network, - traits.getOrganization(), - traits.getUserType(), - traits.getUserCount(), - traits.getStaticIpScore() - ); + public Traits() { + this(null, null, (ConnectionType) null, null, + null, false, false, false, false, + false, false, false, false, null, + null, null, null, null, null, null, null); } /** @@ -251,10 +177,13 @@ public Traits( * >autonomous system number associated with the IP address. This * is only available from the City Plus and Insights web services and * the Enterprise database. + * @deprecated Use {@link #autonomousSystemNumber()} instead. This method will be + * removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("autonomous_system_number") public Long getAutonomousSystemNumber() { - return this.autonomousSystemNumber; + return autonomousSystemNumber(); } /** @@ -263,30 +192,37 @@ public Long getAutonomousSystemNumber() { * >autonomous system number for the IP address. This is only * available from the City Plus and Insights web services and the * Enterprise database. + * @deprecated Use {@link #autonomousSystemOrganization()} instead. This method will be + * removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("autonomous_system_organization") public String getAutonomousSystemOrganization() { - return this.autonomousSystemOrganization; + return autonomousSystemOrganization(); } /** * @return The connection type of the IP address. This is only * available from the City Plus and Insights web services and the * Enterprise database. + * @deprecated Use {@link #connectionType()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("connection_type") public ConnectionType getConnectionType() { - return this.connectionType; + return connectionType(); } /** * @return The static IP score of the IP address. This is an indicator of * how static or dynamic an IP address is. This is only available from * the Insights web service. + * @deprecated Use {@link #staticIpScore()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("static_ip_score") public Double getStaticIpScore() { - return this.staticIpScore; + return staticIpScore(); } /** @@ -294,10 +230,12 @@ public Double getStaticIpScore() { * during the past 24 hours. For IPv4, the count is for the individual * IP address. For IPv6, the count is for the /64 network. This is only * available from the Insights web service. + * @deprecated Use {@link #userCount()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("user_count") public Integer getUserCount() { - return this.userCount; + return userCount(); } /** @@ -305,10 +243,12 @@ public Integer getUserCount() { * will be something like "example.com" or "example.co.uk", not * "foo.example.com". This is only available from the City Plus and * Insights web services and the Enterprise database. + * @deprecated Use {@link #domain()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty public String getDomain() { - return this.domain; + return domain(); } /** @@ -317,100 +257,23 @@ public String getDomain() { * externally routable IP address for the system the code is running * on. If the system is behind a NAT, this may differ from the IP * address locally assigned to it. + * @deprecated Use {@link #ipAddress()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("ip_address") public String getIpAddress() { - return this.ipAddress; + return ipAddress().getHostAddress(); } /** * @return The name of the ISP associated with the IP address. This * is only available from the City Plus and Insights web services and * the Enterprise database. + * @deprecated Use {@link #isp()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) public String getIsp() { - return this.isp; - } - - /** - * @return This is true if the IP address belongs to any sort of anonymous - * network. This is only available from the Insights web service. - */ - @JsonProperty("is_anonymous") - public boolean isAnonymous() { - return this.isAnonymous; - } - - - /** - * @return This is true if the IP address is registered to an anonymous - * VPN provider. If a VPN provider does not register subnets under names - * associated with them, we will likely only flag their IP ranges using - * isHostingProvider. This is only available from the Insights web - * service. - */ - @JsonProperty("is_anonymous_vpn") - public boolean isAnonymousVpn() { - return this.isAnonymousVpn; - } - - /** - * @return This is true if the IP address belongs to an anycast network. - * This is not available from GeoLite databases or web services. - */ - @JsonProperty("is_anycast") - public boolean isAnycast() { - return this.isAnycast; - } - - /** - * @return This is true if the IP address belongs to a hosting or - * VPN provider (see description of isAnonymousVpn). This is only - * available from the Insights web service. - */ - @JsonProperty("is_hosting_provider") - public boolean isHostingProvider() { - return this.isHostingProvider; - } - - /** - * @return This is true if MaxMind believes this IP address to be a - * legitimate proxy, such as an internal VPN used by a corporation. This is - * only available in the Enterprise database. - */ - @JsonProperty("is_legitimate_proxy") - public boolean isLegitimateProxy() { - return this.isLegitimateProxy; - } - - /** - * @return This is true if the IP address belongs to a public proxy. - * This is only available from the Insights web service. - */ - @JsonProperty("is_public_proxy") - public boolean isPublicProxy() { - return this.isPublicProxy; - } - - /** - * @return This is true if the IP address is on a suspected anonymizing - * network and belongs to a residential ISP. This is only available from - * the Insights web service. - */ - @JsonProperty("is_residential_proxy") - public boolean isResidentialProxy() { - return this.isResidentialProxy; - } - - - /** - * @return This is true if the IP address belongs to a Tor exit node. - * This is only available from the Insights web service. - */ - @JsonProperty("is_tor_exit_node") - public boolean isTorExitNode() { - return this.isTorExitNode; + return isp(); } /** @@ -418,10 +281,12 @@ public boolean isTorExitNode() { * mobile country code (MCC) associated with the IP address and ISP. * This is available from the City Plus and Insights web services and the * Enterprise database. + * @deprecated Use {@link #mobileCountryCode()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("mobile_country_code") public String getMobileCountryCode() { - return this.mobileCountryCode; + return mobileCountryCode(); } /** @@ -429,31 +294,37 @@ public String getMobileCountryCode() { * mobile network code (MNC) associated with the IP address and ISP. * This is available from the City Plus and Insights web services and the * Enterprise database. + * @deprecated Use {@link #mobileNetworkCode()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("mobile_network_code") public String getMobileNetworkCode() { - return this.mobileNetworkCode; + return mobileNetworkCode(); } /** * @return The network associated with the record. In particular, this is * the largest network where all the fields besides IP address have the * same value. + * @deprecated Use {@link #network()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty @JsonSerialize(using = ToStringSerializer.class) public Network getNetwork() { - return this.network; + return network(); } /** * @return The name of the organization associated with the IP address. * This is only available from the City Plus and Insights web services and * the Enterprise database. + * @deprecated Use {@link #organization()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty public String getOrganization() { - return this.organization; + return organization(); } /** @@ -483,9 +354,11 @@ public String getOrganization() { * This is only available from the Insights web service and the Enterprise * database. *

+ * @deprecated Use {@link #userType()} instead. This method will be removed in 6.0.0. */ + @Deprecated(since = "5.0.0", forRemoval = true) @JsonProperty("user_type") public String getUserType() { - return this.userType; + return userType(); } } diff --git a/src/test/java/com/maxmind/geoip2/DatabaseReaderTest.java b/src/test/java/com/maxmind/geoip2/DatabaseReaderTest.java index e70b3e05..b92e1a1c 100644 --- a/src/test/java/com/maxmind/geoip2/DatabaseReaderTest.java +++ b/src/test/java/com/maxmind/geoip2/DatabaseReaderTest.java @@ -63,7 +63,7 @@ public void testDefaultLocaleURL() throws Exception { private void testDefaultLocale(DatabaseReader reader) throws IOException, GeoIp2Exception { CityResponse city = reader.city(InetAddress.getByName("81.2.69.160")); - assertEquals("London", city.getCity().getName()); + assertEquals("London", city.city().name()); } @Test @@ -72,8 +72,8 @@ public void testIsInEuropeanUnion() throws Exception { .build() ) { CityResponse city = reader.city(InetAddress.getByName("89.160.20.128")); - assertTrue(city.getCountry().isInEuropeanUnion()); - assertTrue(city.getRegisteredCountry().isInEuropeanUnion()); + assertTrue(city.country().isInEuropeanUnion()); + assertTrue(city.registeredCountry().isInEuropeanUnion()); } } @@ -100,7 +100,7 @@ public void testLocaleListURL() throws Exception { private void testLocaleList(DatabaseReader reader) throws IOException, GeoIp2Exception { CityResponse city = reader.city(InetAddress.getByName("81.2.69.160")); - assertEquals("Лондон", city.getCity().getName()); + assertEquals("Лондон", city.city().name()); } @Test @@ -124,15 +124,15 @@ public void testMemoryModeURL() throws Exception { private void testMemoryMode(DatabaseReader reader) throws IOException, GeoIp2Exception { CityResponse city = reader.city(InetAddress.getByName("81.2.69.160")); - assertEquals("London", city.getCity().getName()); - assertEquals(100, city.getLocation().getAccuracyRadius().longValue()); + assertEquals("London", city.city().name()); + assertEquals(100, city.location().accuracyRadius().longValue()); } @Test public void metadata() throws IOException { DatabaseReader reader = new DatabaseReader.Builder(this.geoipFile) .fileMode(Reader.FileMode.MEMORY).build(); - assertEquals("GeoIP2-City", reader.getMetadata().getDatabaseType()); + assertEquals("GeoIP2-City", reader.metadata().databaseType()); } @Test @@ -156,8 +156,8 @@ public void hasIpAddressURL() throws Exception { private void hasIpInfo(DatabaseReader reader) throws IOException, GeoIp2Exception { CityResponse cio = reader.city(InetAddress.getByName("81.2.69.160")); - assertEquals("81.2.69.160", cio.getTraits().getIpAddress()); - assertEquals("81.2.69.160/27", cio.getTraits().getNetwork().toString()); + assertEquals("81.2.69.160", cio.traits().ipAddress().getHostAddress()); + assertEquals("81.2.69.160/27", cio.traits().network().toString()); } @Test @@ -220,8 +220,8 @@ public void testAnonymousIp() throws Exception { assertFalse(response.isPublicProxy()); assertFalse(response.isResidentialProxy()); assertFalse(response.isTorExitNode()); - assertEquals(ipAddress.getHostAddress(), response.getIpAddress()); - assertEquals("1.2.0.0/16", response.getNetwork().toString()); + assertEquals(ipAddress.getHostAddress(), response.ipAddress().getHostAddress()); + assertEquals("1.2.0.0/16", response.network().toString()); AnonymousIpResponse tryResponse = reader.tryAnonymousIp(ipAddress).get(); assertEquals(response.toJson(), tryResponse.toJson()); @@ -235,17 +235,17 @@ public void testAnonymousPlus() throws Exception { ) { InetAddress ipAddress = InetAddress.getByName("1.2.0.1"); AnonymousPlusResponse response = reader.anonymousPlus(ipAddress); - assertEquals(30, response.getAnonymizerConfidence()); + assertEquals(30, response.anonymizerConfidence()); assertTrue(response.isAnonymous()); assertTrue(response.isAnonymousVpn()); assertFalse(response.isHostingProvider()); assertFalse(response.isPublicProxy()); assertFalse(response.isResidentialProxy()); assertFalse(response.isTorExitNode()); - assertEquals(ipAddress.getHostAddress(), response.getIpAddress()); - assertEquals("1.2.0.1/32", response.getNetwork().toString()); - assertEquals("2025-04-14", response.getNetworkLastSeen().toString()); - assertEquals("foo", response.getProviderName()); + assertEquals(ipAddress.getHostAddress(), response.ipAddress().getHostAddress()); + assertEquals("1.2.0.1/32", response.network().toString()); + assertEquals("2025-04-14", response.networkLastSeen().toString()); + assertEquals("foo", response.providerName()); AnonymousPlusResponse tryResponse = reader.tryAnonymousPlus(ipAddress).get(); assertEquals(response.toJson(), tryResponse.toJson()); @@ -270,11 +270,11 @@ public void testAsn() throws Exception { ) { InetAddress ipAddress = InetAddress.getByName("1.128.0.0"); AsnResponse response = reader.asn(ipAddress); - assertEquals(1221, response.getAutonomousSystemNumber().intValue()); + assertEquals(1221, response.autonomousSystemNumber().intValue()); assertEquals("Telstra Pty Ltd", - response.getAutonomousSystemOrganization()); - assertEquals(ipAddress.getHostAddress(), response.getIpAddress()); - assertEquals("1.128.0.0/11", response.getNetwork().toString()); + response.autonomousSystemOrganization()); + assertEquals(ipAddress.getHostAddress(), response.ipAddress().getHostAddress()); + assertEquals("1.128.0.0/11", response.network().toString()); AsnResponse tryResponse = reader.tryAsn(ipAddress).get(); assertEquals(response.toJson(), tryResponse.toJson()); @@ -289,18 +289,18 @@ public void testCity() throws Exception { InetAddress ipAddress = InetAddress.getByName("81.2.69.192"); CityResponse response = reader.city(ipAddress); - assertEquals(2635167, response.getCountry().getGeoNameId().intValue()); - assertEquals(100, response.getLocation().getAccuracyRadius().intValue()); - assertFalse(response.getTraits().isLegitimateProxy()); - assertEquals(ipAddress.getHostAddress(), response.getTraits().getIpAddress()); - assertEquals("81.2.69.192/28", response.getTraits().getNetwork().toString()); + assertEquals(2635167, response.country().geonameId().intValue()); + assertEquals(100, response.location().accuracyRadius().intValue()); + assertFalse(response.traits().isLegitimateProxy()); + assertEquals(ipAddress.getHostAddress(), response.traits().ipAddress().getHostAddress()); + assertEquals("81.2.69.192/28", response.traits().network().toString()); CityResponse tryResponse = reader.tryCity(ipAddress).get(); assertEquals(response.toJson(), tryResponse.toJson()); // This IP has is_anycast response = reader.city(InetAddress.getByName("214.1.1.0")); - assertTrue(response.getTraits().isAnycast()); + assertTrue(response.traits().isAnycast()); // Test that the methods can be called on DB without // an exception @@ -317,9 +317,9 @@ public void testConnectionType() throws Exception { ConnectionTypeResponse response = reader.connectionType(ipAddress); - assertEquals(ConnectionType.CELLULAR, response.getConnectionType()); - assertEquals(ipAddress.getHostAddress(), response.getIpAddress()); - assertEquals("1.0.1.0/24", response.getNetwork().toString()); + assertEquals(ConnectionType.CELLULAR, response.connectionType()); + assertEquals(ipAddress.getHostAddress(), response.ipAddress().getHostAddress()); + assertEquals("1.0.1.0/24", response.network().toString()); ConnectionTypeResponse tryResponse = reader.tryConnectionType(ipAddress).get(); assertEquals(response.toJson(), tryResponse.toJson()); @@ -334,18 +334,18 @@ public void testCountry() throws Exception { InetAddress ipAddress = InetAddress.getByName("74.209.24.0"); CountryResponse response = reader.country(ipAddress); - assertEquals("NA", response.getContinent().getCode()); - assertEquals(6252001, response.getCountry().getGeoNameId().intValue()); - assertEquals(6252001, response.getRegisteredCountry().getGeoNameId().intValue()); - assertEquals(ipAddress.getHostAddress(), response.getTraits().getIpAddress()); - assertEquals("74.209.16.0/20", response.getTraits().getNetwork().toString()); + assertEquals("NA", response.continent().code()); + assertEquals(6252001, response.country().geonameId().intValue()); + assertEquals(6252001, response.registeredCountry().geonameId().intValue()); + assertEquals(ipAddress.getHostAddress(), response.traits().ipAddress().getHostAddress()); + assertEquals("74.209.16.0/20", response.traits().network().toString()); CountryResponse tryResponse = reader.tryCountry(ipAddress).get(); assertEquals(response.toJson(), tryResponse.toJson()); // This IP has is_anycast response = reader.country(InetAddress.getByName("214.1.1.0")); - assertTrue(response.getTraits().isAnycast()); + assertTrue(response.traits().isAnycast()); } } @@ -356,9 +356,9 @@ public void testDomain() throws Exception { ) { InetAddress ipAddress = InetAddress.getByName("1.2.0.0"); DomainResponse response = reader.domain(ipAddress); - assertEquals("maxmind.com", response.getDomain()); - assertEquals(ipAddress.getHostAddress(), response.getIpAddress()); - assertEquals("1.2.0.0/16", response.getNetwork().toString()); + assertEquals("maxmind.com", response.domain()); + assertEquals(ipAddress.getHostAddress(), response.ipAddress().getHostAddress()); + assertEquals("1.2.0.0/16", response.network().toString()); DomainResponse tryResponse = reader.tryDomain(ipAddress).get(); assertEquals(response.toJson(), tryResponse.toJson()); @@ -373,26 +373,26 @@ public void testEnterprise() throws Exception { InetAddress ipAddress = InetAddress.getByName("74.209.24.0"); EnterpriseResponse response = reader.enterprise(ipAddress); - assertEquals(11, response.getCity().getConfidence().intValue()); - assertEquals(99, response.getCountry().getConfidence().intValue()); - assertEquals(6252001, response.getCountry().getGeoNameId().intValue()); - assertEquals(27, response.getLocation().getAccuracyRadius().intValue()); - assertEquals(ConnectionType.CABLE_DSL, response.getTraits().getConnectionType()); - assertTrue(response.getTraits().isLegitimateProxy()); - assertEquals(ipAddress.getHostAddress(), response.getTraits().getIpAddress()); - assertEquals("74.209.16.0/20", response.getTraits().getNetwork().toString()); + assertEquals(11, response.city().confidence().intValue()); + assertEquals(99, response.country().confidence().intValue()); + assertEquals(6252001, response.country().geonameId().intValue()); + assertEquals(27, response.location().accuracyRadius().intValue()); + assertEquals(ConnectionType.CABLE_DSL, response.traits().connectionType()); + assertTrue(response.traits().isLegitimateProxy()); + assertEquals(ipAddress.getHostAddress(), response.traits().ipAddress().getHostAddress()); + assertEquals("74.209.16.0/20", response.traits().network().toString()); EnterpriseResponse tryResponse = reader.tryEnterprise(ipAddress).get(); assertEquals(response.toJson(), tryResponse.toJson()); ipAddress = InetAddress.getByName("149.101.100.0"); response = reader.enterprise(ipAddress); - assertEquals("310", response.getTraits().getMobileCountryCode()); - assertEquals("004", response.getTraits().getMobileNetworkCode()); + assertEquals("310", response.traits().mobileCountryCode()); + assertEquals("004", response.traits().mobileNetworkCode()); // This IP has is_anycast response = reader.enterprise(InetAddress.getByName("214.1.1.0")); - assertTrue(response.getTraits().isAnycast()); + assertTrue(response.traits().isAnycast()); // Test that the city and country methods can be called without // an exception @@ -408,22 +408,22 @@ public void testIsp() throws Exception { ) { InetAddress ipAddress = InetAddress.getByName("1.128.0.0"); IspResponse response = reader.isp(ipAddress); - assertEquals(1221, response.getAutonomousSystemNumber().intValue()); + assertEquals(1221, response.autonomousSystemNumber().intValue()); assertEquals("Telstra Pty Ltd", - response.getAutonomousSystemOrganization()); - assertEquals("Telstra Internet", response.getIsp()); - assertEquals("Telstra Internet", response.getOrganization()); + response.autonomousSystemOrganization()); + assertEquals("Telstra Internet", response.isp()); + assertEquals("Telstra Internet", response.organization()); - assertEquals(ipAddress.getHostAddress(), response.getIpAddress()); - assertEquals("1.128.0.0/11", response.getNetwork().toString()); + assertEquals(ipAddress.getHostAddress(), response.ipAddress().getHostAddress()); + assertEquals("1.128.0.0/11", response.network().toString()); IspResponse tryResponse = reader.tryIsp(ipAddress).get(); assertEquals(response.toJson(), tryResponse.toJson()); ipAddress = InetAddress.getByName("149.101.100.0"); response = reader.isp(ipAddress); - assertEquals("310", response.getMobileCountryCode()); - assertEquals("004", response.getMobileNetworkCode()); + assertEquals("310", response.mobileCountryCode()); + assertEquals("004", response.mobileNetworkCode()); } } diff --git a/src/test/java/com/maxmind/geoip2/NetworkDeserializerTest.java b/src/test/java/com/maxmind/geoip2/NetworkDeserializerTest.java index 60acf26d..35b2d57c 100644 --- a/src/test/java/com/maxmind/geoip2/NetworkDeserializerTest.java +++ b/src/test/java/com/maxmind/geoip2/NetworkDeserializerTest.java @@ -23,8 +23,8 @@ private static Network parse(String jsonString) throws IOException { } private static void assertNetwork(Network n, String addr, int prefix) throws Exception { assertNotNull(n); - assertEquals(InetAddress.getByName(addr), n.getNetworkAddress()); - assertEquals(prefix, n.getPrefixLength()); + assertEquals(InetAddress.getByName(addr), n.networkAddress()); + assertEquals(prefix, n.prefixLength()); } @Test diff --git a/src/test/java/com/maxmind/geoip2/WebServiceClientTest.java b/src/test/java/com/maxmind/geoip2/WebServiceClientTest.java index 03500381..cd5c2af0 100644 --- a/src/test/java/com/maxmind/geoip2/WebServiceClientTest.java +++ b/src/test/java/com/maxmind/geoip2/WebServiceClientTest.java @@ -25,7 +25,6 @@ import com.maxmind.geoip2.exception.OutOfQueriesException; import com.maxmind.geoip2.exception.PermissionRequiredException; import com.maxmind.geoip2.model.InsightsResponse; -import com.maxmind.geoip2.record.AbstractNamedRecord; import com.maxmind.geoip2.record.City; import com.maxmind.geoip2.record.Continent; import com.maxmind.geoip2.record.Country; @@ -71,7 +70,6 @@ public void test200WithInvalidJson() throws Exception { assertEquals("Received a 200 response but could not decode it as JSON", ex.getMessage()); } - @SuppressWarnings("deprecation") @Test public void test200WithDefaultValues() throws Exception { WebServiceClient client = createSuccessClient("insights", "1.2.3.13", @@ -81,93 +79,98 @@ public void test200WithDefaultValues() throws Exception { .getByName("1.2.3.13")); assertThat(insights.toString(), - CoreMatchers.startsWith("com.maxmind.geoip2.model.InsightsResponse [ {")); + CoreMatchers.startsWith("InsightsResponse[")); - City city = insights.getCity(); + City city = insights.city(); assertNotNull(city); - assertNull(city.getConfidence()); + assertNull(city.confidence()); - Continent continent = insights.getContinent(); + Continent continent = insights.continent(); assertNotNull(continent); - assertNull(continent.getCode()); + assertNull(continent.code()); - Country country = insights.getCountry(); + Country country = insights.country(); assertNotNull(country); - Location location = insights.getLocation(); + Location location = insights.location(); assertNotNull(location); - assertNull(location.getAccuracyRadius()); - assertNull(location.getLatitude()); - assertNull(location.getLongitude()); - assertNull(location.getTimeZone()); + assertNull(location.accuracyRadius()); + assertNull(location.latitude()); + assertNull(location.longitude()); + assertNull(location.timeZone()); assertThat(location.toString(), - CoreMatchers.equalTo("com.maxmind.geoip2.record.Location [ {} ]")); + CoreMatchers.startsWith("Location[")); - MaxMind maxmind = insights.getMaxMind(); + MaxMind maxmind = insights.maxmind(); assertNotNull(maxmind); - assertNull(maxmind.getQueriesRemaining()); + assertNull(maxmind.queriesRemaining()); - assertNotNull(insights.getPostal()); + assertNotNull(insights.postal()); - Country registeredCountry = insights.getRegisteredCountry(); + Country registeredCountry = insights.registeredCountry(); assertNotNull(registeredCountry); RepresentedCountry representedCountry = insights - .getRepresentedCountry(); + .representedCountry(); assertNotNull(representedCountry); - assertNull(representedCountry.getType()); + assertNull(representedCountry.type()); - List subdivisions = insights.getSubdivisions(); + List subdivisions = insights.subdivisions(); assertNotNull(subdivisions); assertTrue(subdivisions.isEmpty()); - Subdivision subdiv = insights.getMostSpecificSubdivision(); + Subdivision subdiv = insights.mostSpecificSubdivision(); assertNotNull(subdiv); - assertNull(subdiv.getIsoCode()); - assertNull(subdiv.getConfidence()); + assertNull(subdiv.isoCode()); + assertNull(subdiv.confidence()); - Subdivision leastSpecificSubdiv = insights.getLeastSpecificSubdivision(); + Subdivision leastSpecificSubdiv = insights.leastSpecificSubdivision(); assertNotNull(leastSpecificSubdiv); - assertNull(leastSpecificSubdiv.getIsoCode()); - assertNull(leastSpecificSubdiv.getConfidence()); + assertNull(leastSpecificSubdiv.isoCode()); + assertNull(leastSpecificSubdiv.confidence()); - Traits traits = insights.getTraits(); + Traits traits = insights.traits(); assertNotNull(traits); - assertNull(traits.getAutonomousSystemNumber()); - assertNull(traits.getAutonomousSystemOrganization()); - assertNull(traits.getConnectionType()); - assertNull(traits.getDomain()); - assertEquals("1.2.3.13", traits.getIpAddress()); - assertEquals("1.2.3.0/24", traits.getNetwork().toString()); - assertNull(traits.getIsp()); - assertNull(traits.getOrganization()); - assertNull(traits.getUserType()); - assertNull(traits.getStaticIpScore()); - assertNull(traits.getUserCount()); + assertNull(traits.autonomousSystemNumber()); + assertNull(traits.autonomousSystemOrganization()); + assertNull(traits.connectionType()); + assertNull(traits.domain()); + assertEquals("1.2.3.13", traits.ipAddress().getHostAddress()); + assertEquals("1.2.3.0/24", traits.network().toString()); + assertNull(traits.isp()); + assertNull(traits.organization()); + assertNull(traits.userType()); + assertNull(traits.staticIpScore()); + assertNull(traits.userCount()); assertFalse(traits.isAnycast()); - for (Country c : new Country[] {country, registeredCountry, - representedCountry}) { - assertNull(c.getConfidence()); - assertNull(c.getIsoCode()); + for (Country c : new Country[] {country, registeredCountry}) { + assertNull(c.confidence()); + assertNull(c.isoCode()); assertFalse(c.isInEuropeanUnion()); } - for (AbstractNamedRecord r : new AbstractNamedRecord[] {city, + // Check RepresentedCountry separately since it's no longer a Country + assertNull(representedCountry.confidence()); + assertNull(representedCountry.isoCode()); + assertFalse(representedCountry.isInEuropeanUnion()); + + for (NamedRecord r : new NamedRecord[] {city, continent, subdiv}) { - assertNull(r.getGeoNameId()); - assertNull(r.getName()); - assertTrue(r.getNames().isEmpty()); - assertEquals(r.getClass().getName() + " [ {} ]", r.toString()); + assertNull(r.geonameId()); + assertNull(r.name()); + assertTrue(r.names().isEmpty()); + // Records have their own toString format + assertNotNull(r.toString()); } - for (AbstractNamedRecord r : new AbstractNamedRecord[] {country, + for (NamedRecord r : new NamedRecord[] {country, registeredCountry, representedCountry}) { - assertNull(r.getGeoNameId()); - assertNull(r.getName()); - assertTrue(r.getNames().isEmpty()); - assertEquals(r.getClass().getName() + - " [ {\"is_in_european_union\":false} ]", r.toString()); + assertNull(r.geonameId()); + assertNull(r.name()); + assertTrue(r.names().isEmpty()); + // Records have their own toString format + assertNotNull(r.toString()); } } @@ -176,7 +179,7 @@ public void test200OnInsightsAsMe() throws Exception { WebServiceClient client = createSuccessClient("insights", "me", "{\"traits\":{\"ip_address\":\"24.24.24.24\"}}"); assertEquals("24.24.24.24", - client.insights().getTraits().getIpAddress()); + client.insights().traits().ipAddress().getHostAddress()); } @Test @@ -184,7 +187,7 @@ public void test200OnCityAsMe() throws Exception { WebServiceClient client = createSuccessClient("city", "me", "{\"traits\":{\"ip_address\":\"24.24.24.24\"}}"); assertEquals("24.24.24.24", - client.city().getTraits().getIpAddress()); + client.city().traits().ipAddress().getHostAddress()); } @Test @@ -192,7 +195,7 @@ public void test200OnCountryAsMe() throws Exception { WebServiceClient client = createSuccessClient("country", "me", "{\"traits\":{\"ip_address\":\"24.24.24.24\"}}"); assertEquals("24.24.24.24", - client.country().getTraits().getIpAddress()); + client.country().traits().ipAddress().getHostAddress()); } @Test diff --git a/src/test/java/com/maxmind/geoip2/matchers/CodeMatcher.java b/src/test/java/com/maxmind/geoip2/matchers/CodeMatcher.java index 9b1cb00f..bef6fe21 100644 --- a/src/test/java/com/maxmind/geoip2/matchers/CodeMatcher.java +++ b/src/test/java/com/maxmind/geoip2/matchers/CodeMatcher.java @@ -19,7 +19,7 @@ private CodeMatcher(String expectedErrorCode) { @Override protected boolean matchesSafely(final InvalidRequestException exception) { - this.foundErrorCode = exception.getCode(); + this.foundErrorCode = exception.code(); return this.foundErrorCode.equalsIgnoreCase(this.expectedErrorCode); } diff --git a/src/test/java/com/maxmind/geoip2/matchers/HttpStatusMatcher.java b/src/test/java/com/maxmind/geoip2/matchers/HttpStatusMatcher.java index 9704e309..8d192138 100644 --- a/src/test/java/com/maxmind/geoip2/matchers/HttpStatusMatcher.java +++ b/src/test/java/com/maxmind/geoip2/matchers/HttpStatusMatcher.java @@ -19,7 +19,7 @@ private HttpStatusMatcher(int expectedStatusCode) { @Override protected boolean matchesSafely(final HttpException exception) { - this.foundStatusCode = exception.getHttpStatus(); + this.foundStatusCode = exception.httpStatus(); return this.foundStatusCode == this.expectedStatusCode; } diff --git a/src/test/java/com/maxmind/geoip2/model/CityResponseTest.java b/src/test/java/com/maxmind/geoip2/model/CityResponseTest.java index 5b080e73..a9dce2a6 100644 --- a/src/test/java/com/maxmind/geoip2/model/CityResponseTest.java +++ b/src/test/java/com/maxmind/geoip2/model/CityResponseTest.java @@ -55,17 +55,17 @@ public void testNames() throws Exception { CityResponse city = client.city(InetAddress.getByName("1.1.1.2")); assertEquals( "北美洲", - city.getContinent().getName(), - "country.getContinent().getName() does not return 北美洲" + city.continent().name(), + "country.continent().name() does not return 北美洲" ); assertEquals( "美国", - city.getCountry().getName(), - "country.getCountry().getName() does not return 美国" + city.country().name(), + "country.country().name() does not return 美国" ); assertEquals( - city.getCountry() - .getName(), city.getCountry().getName(), + city.country() + .name(), city.country().name(), "toString() returns getName()" ); } @@ -82,8 +82,8 @@ public void russianFallback() throws Exception { CityResponse city = client.city(InetAddress.getByName("1.1.1.2")); assertEquals( "объединяет государства", - city.getCountry().getName(), - "country.getCountry().getName() does not return объединяет государства" + city.country().name(), + "country.country().name() does not return объединяет государства" ); } @@ -99,7 +99,7 @@ public void testFallback() throws Exception { CityResponse city = client.city(InetAddress.getByName("1.1.1.2")); assertEquals( "North America", - city.getContinent().getName(), + city.continent().name(), "en is returned when pt is missing" ); @@ -116,7 +116,7 @@ public void noFallback() throws Exception { CityResponse city = client.city(InetAddress.getByName("1.1.1.2")); assertNull( - city.getContinent().getName(), + city.continent().name(), "null is returned when locale is not available" ); } @@ -132,7 +132,7 @@ public void noLocale() throws Exception { CityResponse city = client.city(InetAddress.getByName("1.1.1.2")); assertEquals( "North America", - city.getContinent().getName(), + city.continent().name(), "en is returned when no locales are specified" ); @@ -148,7 +148,7 @@ public void testMissing() throws Exception { .locales(Collections.singletonList("en")).build(); CityResponse city = client.city(InetAddress.getByName("1.1.1.2")); - assertNotNull(city.getCity()); - assertNull(city.getCity().getName(), "null is returned when names object is missing"); + assertNotNull(city.city()); + assertNull(city.city().name(), "null is returned when names object is missing"); } } diff --git a/src/test/java/com/maxmind/geoip2/model/CountryResponseTest.java b/src/test/java/com/maxmind/geoip2/model/CountryResponseTest.java index 9535f077..d0a7c415 100644 --- a/src/test/java/com/maxmind/geoip2/model/CountryResponseTest.java +++ b/src/test/java/com/maxmind/geoip2/model/CountryResponseTest.java @@ -52,97 +52,97 @@ public void createClient() throws IOException, GeoIp2Exception, public void testContinent() { assertEquals( "NA", - this.country.getContinent().getCode(), - "country.getContinent().getCode() does not return NA" + this.country.continent().code(), + "country.continent().code() does not return NA" ); assertEquals( 42, - this.country.getContinent().getGeoNameId(), - "country.getContinent().getGeoNameId() does not return 42" + this.country.continent().geonameId(), + "country.continent().geonameId() does not return 42" ); assertEquals( "North America", - this.country.getContinent().getName(), - "country.getContinent().getName() does not return North America" + this.country.continent().name(), + "country.continent().name() does not return North America" ); } @Test public void testCountry() { assertFalse( - this.country.getCountry().isInEuropeanUnion(), - "country.getCountry().isInEuropeanUnion() does not return false" + this.country.country().isInEuropeanUnion(), + "country.country().isInEuropeanUnion() does not return false" ); assertEquals( - this.country.getCountry().getIsoCode(), + this.country.country().isoCode(), "US", - "country.getCountry().getCode() does not return US" + "country.country().code() does not return US" ); assertEquals( 1, - (long) this.country.getCountry().getGeoNameId(), - "country.getCountry().getGeoNameId() does not return 1" + (long) this.country.country().geonameId(), + "country.country().geonameId() does not return 1" ); assertEquals( Integer.valueOf(56), - this.country.getCountry().getConfidence(), - "country.getCountry().getConfidence() does not return 56" + this.country.country().confidence(), + "country.country().confidence() does not return 56" ); assertEquals( "United States", - this.country.getCountry().getName(), - "country.getCountry().getName(\"en\") does not return United States" + this.country.country().name(), + "country.country().name(\"en\") does not return United States" ); } @Test public void testRegisteredCountry() { assertFalse( - this.country.getRegisteredCountry().isInEuropeanUnion(), - "country.getRegisteredCountry().isInEuropeanUnion() does not return false" + this.country.registeredCountry().isInEuropeanUnion(), + "country.registeredCountry().isInEuropeanUnion() does not return false" ); assertEquals( "CA", - this.country.getRegisteredCountry().getIsoCode(), - "country.getRegisteredCountry().getIsoCode() does not return CA" + this.country.registeredCountry().isoCode(), + "country.registeredCountry().isoCode() does not return CA" ); assertEquals( 2, - (long) this.country.getRegisteredCountry().getGeoNameId(), - "country.getRegisteredCountry().getGeoNameId() does not return 2" + (long) this.country.registeredCountry().geonameId(), + "country.registeredCountry().geonameId() does not return 2" ); assertEquals( "Canada", - this.country.getRegisteredCountry().getName(), - "country.getRegisteredCountry().getName(\"en\") does not return United States" + this.country.registeredCountry().name(), + "country.registeredCountry().name(\"en\") does not return United States" ); } @Test public void testRepresentedCountry() { assertTrue( - this.country.getRepresentedCountry().isInEuropeanUnion(), - "country.getRepresentedCountry().isInEuropeanUnion() does not return true" + this.country.representedCountry().isInEuropeanUnion(), + "country.representedCountry().isInEuropeanUnion() does not return true" ); assertEquals( "GB", - this.country.getRepresentedCountry().getIsoCode(), - "country.getRepresentedCountry().getCode() does not return GB" + this.country.representedCountry().isoCode(), + "country.representedCountry().code() does not return GB" ); assertEquals( 4, - (long) this.country.getRepresentedCountry().getGeoNameId(), - "country.getRepresentedCountry().getGeoNameId() does not return 4" + (long) this.country.representedCountry().geonameId(), + "country.representedCountry().geonameId() does not return 4" ); assertEquals( "United Kingdom", - this.country.getRepresentedCountry().getName(), - "country.getRepresentedCountry().getName(\"en\") does not return United Kingdom" + this.country.representedCountry().name(), + "country.representedCountry().name(\"en\") does not return United Kingdom" ); assertEquals( "military", - this.country.getRepresentedCountry().getType(), - "country.getRepresentedCountry().getType() does not return military" + this.country.representedCountry().type(), + "country.representedCountry().type() does not return military" ); } @@ -151,8 +151,8 @@ public void testTraits() { assertEquals( "1.2.3.4", - this.country.getTraits().getIpAddress(), - "country.getTraits().getIpAddress does not return 1.2.3.4" + this.country.traits().ipAddress().getHostAddress(), + "country.traits().getIpAddress does not return 1.2.3.4" ); } diff --git a/src/test/java/com/maxmind/geoip2/model/InsightsResponseTest.java b/src/test/java/com/maxmind/geoip2/model/InsightsResponseTest.java index 34dab71e..ae76aed2 100644 --- a/src/test/java/com/maxmind/geoip2/model/InsightsResponseTest.java +++ b/src/test/java/com/maxmind/geoip2/model/InsightsResponseTest.java @@ -64,7 +64,7 @@ public void createClient() throws IOException, GeoIp2Exception, @Test public void testSubdivisionsList() { - List subdivisionsList = this.insights.getSubdivisions(); + List subdivisionsList = this.insights.subdivisions(); assertNotNull(subdivisionsList, "city.getSubdivisionsList returns null"); if (subdivisionsList.isEmpty()) { fail("subdivisionsList is empty"); @@ -72,18 +72,18 @@ public void testSubdivisionsList() { Subdivision subdivision = subdivisionsList.get(0); assertEquals( Integer.valueOf(88), - subdivision.getConfidence(), - "subdivision.getConfidence() does not return 88" + subdivision.confidence(), + "subdivision.confidence() does not return 88" ); assertEquals( 574635, - subdivision.getGeoNameId().intValue(), - "subdivision.getGeoNameId() does not return 574635" + subdivision.geonameId().intValue(), + "subdivision.geonameId() does not return 574635" ); assertEquals( "MN", - subdivision.getIsoCode(), - "subdivision.getCode() does not return MN" + subdivision.isoCode(), + "subdivision.code() does not return MN" ); } @@ -91,7 +91,7 @@ public void testSubdivisionsList() { public void mostSpecificSubdivision() { assertEquals( "TT", - this.insights.getMostSpecificSubdivision().getIsoCode(), + this.insights.mostSpecificSubdivision().isoCode(), "Most specific subdivision returns last subdivision" ); } @@ -100,43 +100,42 @@ public void mostSpecificSubdivision() { public void leastSpecificSubdivision() { assertEquals( "MN", - this.insights.getLeastSpecificSubdivision().getIsoCode(), + this.insights.leastSpecificSubdivision().isoCode(), "Most specific subdivision returns first subdivision" ); } - @SuppressWarnings("deprecation") @Test public void testTraits() { - Traits traits = this.insights.getTraits(); + Traits traits = this.insights.traits(); - assertNotNull(traits, "city.getTraits() returns null"); + assertNotNull(traits, "city.traits() returns null"); assertEquals( Long.valueOf(1234), - traits.getAutonomousSystemNumber(), - "traits.getAutonomousSystemNumber() does not return 1234" + traits.autonomousSystemNumber(), + "traits.autonomousSystemNumber() does not return 1234" ); assertEquals( "AS Organization", - traits.getAutonomousSystemOrganization(), - "traits.getAutonomousSystemOrganization() does not return AS Organization" + traits.autonomousSystemOrganization(), + "traits.autonomousSystemOrganization() does not return AS Organization" ); assertEquals( ConnectionType.CABLE_DSL, - traits.getConnectionType(), - "traits.getConnectionType() does not return Cable/DSL" + traits.connectionType(), + "traits.connectionType() does not return Cable/DSL" ); assertEquals( "example.com", - traits.getDomain(), - "traits.getDomain() does not return example.com" + traits.domain(), + "traits.domain() does not return example.com" ); assertEquals( "1.2.3.4", - traits.getIpAddress(), - "traits.getIpAddress() does not return 1.2.3.4" + traits.ipAddress().getHostAddress(), + "traits.ipAddress() does not return 1.2.3.4" ); assertTrue(traits.isAnonymous(), "traits.isAnonymous() returns true"); assertTrue(traits.isAnonymousVpn(), "traits.isAnonymousVpn() returns true"); @@ -146,83 +145,82 @@ public void testTraits() { assertTrue(traits.isTorExitNode(), "traits.isTorExitNode() returns true"); assertEquals( "Comcast", - traits.getIsp(), - "traits.getIsp() does not return Comcast" + traits.isp(), + "traits.isp() does not return Comcast" ); assertEquals( "Blorg", - traits.getOrganization(), - "traits.getOrganization() does not return Blorg" + traits.organization(), + "traits.organization() does not return Blorg" ); assertEquals( "college", - traits.getUserType(), - "traits.getUserType() does not return userType" + traits.userType(), + "traits.userType() does not return userType" ); assertEquals( Double.valueOf(1.3), - traits.getStaticIpScore(), - "traits.getStaticIpScore() does not return 1.3" + traits.staticIpScore(), + "traits.staticIpScore() does not return 1.3" ); assertEquals( Integer.valueOf(2), - traits.getUserCount(), - "traits.getUserCount() does not return 2" + traits.userCount(), + "traits.userCount() does not return 2" ); } - @SuppressWarnings("deprecation") @Test public void testLocation() { - Location location = this.insights.getLocation(); + Location location = this.insights.location(); - assertNotNull(location, "city.getLocation() returns null"); + assertNotNull(location, "city.location() returns null"); assertEquals( Integer.valueOf(24626), - location.getAverageIncome(), - "location.getAverageIncome() does not return 24626" + location.averageIncome(), + "location.averageIncome() does not return 24626" ); assertEquals( Integer.valueOf(1500), - location.getAccuracyRadius(), - "location.getAccuracyRadius() does not return 1500" + location.accuracyRadius(), + "location.accuracyRadius() does not return 1500" ); - double latitude = location.getLatitude(); + double latitude = location.latitude(); assertEquals( 44.98, latitude, 0.1, - "location.getLatitude() does not return 44.98" + "location.latitude() does not return 44.98" ); - double longitude = location.getLongitude(); + double longitude = location.longitude(); assertEquals( 93.2636, longitude, 0.1, - "location.getLongitude() does not return 93.2636" + "location.longitude() does not return 93.2636" ); assertEquals( Integer.valueOf(1341), - location.getPopulationDensity(), - "location.getPopulationDensity() does not return 1341" + location.populationDensity(), + "location.populationDensity() does not return 1341" ); assertEquals( "America/Chicago", - location.getTimeZone(), - "location.getTimeZone() does not return America/Chicago" + location.timeZone(), + "location.timeZone() does not return America/Chicago" ); } @Test public void testMaxMind() { - MaxMind maxmind = this.insights.getMaxMind(); + MaxMind maxmind = this.insights.maxmind(); assertEquals( 11, maxmind - .getQueriesRemaining().intValue(), + .queriesRemaining().intValue(), "Correct number of queries remaining" ); } @@ -230,34 +228,34 @@ public void testMaxMind() { @Test public void testPostal() { - Postal postal = this.insights.getPostal(); + Postal postal = this.insights.postal(); assertEquals( "55401", - postal.getCode(), - "postal.getCode() does not return 55401" + postal.code(), + "postal.code() does not return 55401" ); assertEquals( Integer.valueOf(33), - postal.getConfidence(), - "postal.getConfidence() does not return 33" + postal.confidence(), + "postal.confidence() does not return 33" ); } @Test public void testRepresentedCountry() { assertNotNull( - this.insights.getRepresentedCountry(), - "city.getRepresentedCountry() returns null" + this.insights.representedCountry(), + "city.representedCountry() returns null" ); assertEquals( "C", - this.insights.getRepresentedCountry().getType(), - "city.getRepresentedCountry().getType() does not return C" + this.insights.representedCountry().type(), + "city.representedCountry().type() does not return C" ); assertTrue( - this.insights.getRepresentedCountry().isInEuropeanUnion(), - "city.getRepresentedCountry().isInEuropeanUnion() does not return true" + this.insights.representedCountry().isInEuropeanUnion(), + "city.representedCountry().isInEuropeanUnion() does not return true" ); } @@ -276,11 +274,11 @@ public void testIsInEuropeanUnion() throws IOException, GeoIp2Exception { InetAddress.getByName("1.1.1.2")); assertTrue( - insights.getCountry().isInEuropeanUnion(), + insights.country().isInEuropeanUnion(), "getCountry().isInEuropeanUnion() does not return true" ); assertTrue( - insights.getRegisteredCountry().isInEuropeanUnion(), + insights.registeredCountry().isInEuropeanUnion(), "getRegisteredCountry().() isInEuropeanUnion = does not return true" ); } diff --git a/src/test/java/com/maxmind/geoip2/model/JsonTest.java b/src/test/java/com/maxmind/geoip2/model/JsonTest.java index 1a59fce6..73aab8da 100644 --- a/src/test/java/com/maxmind/geoip2/model/JsonTest.java +++ b/src/test/java/com/maxmind/geoip2/model/JsonTest.java @@ -329,11 +329,12 @@ public void testIspSerialization() throws Exception { testRoundTrip(IspResponse.class, json); } - protected void testRoundTrip + protected void testRoundTrip (Class cls, String json) throws IOException { JsonMapper mapper = JsonMapper.builder() .disable(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS) + .addModule(new com.maxmind.geoip2.InetAddressModule()) .build(); InjectableValues inject = new InjectableValues.Std().addValue( "locales", Collections.singletonList("en"));