diff --git a/CHANGELOG.md b/CHANGELOG.md index 4eb4aba4..c0086205 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ CHANGELOG ------------------- * The HTTP client now allows up to 20 connections to be active at once. Previously the limit was 2. +* Update `maxmind-db` dependency to a new version that no longer uses + Jackson. This improves database lookup performance. 2.14.0 (2020-06-15) ------------------- diff --git a/sample/Benchmark.java b/sample/Benchmark.java index 1f5d34cf..2d760803 100644 --- a/sample/Benchmark.java +++ b/sample/Benchmark.java @@ -65,4 +65,4 @@ private static void bench(DatabaseReader r, int count, int seed) throws GeoIp2Ex long qps = count * 1000000000L / duration; System.out.println("Requests per second: " + qps); } -} \ No newline at end of file +} diff --git a/src/main/java/com/maxmind/geoip2/DatabaseReader.java b/src/main/java/com/maxmind/geoip2/DatabaseReader.java index 0b63977d..ba9f9903 100644 --- a/src/main/java/com/maxmind/geoip2/DatabaseReader.java +++ b/src/main/java/com/maxmind/geoip2/DatabaseReader.java @@ -1,7 +1,5 @@ package com.maxmind.geoip2; -import com.fasterxml.jackson.databind.*; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.maxmind.db.*; import com.maxmind.db.Reader.FileMode; import com.maxmind.geoip2.exception.AddressNotFoundException; @@ -65,8 +63,6 @@ public class DatabaseReader implements DatabaseProvider, Closeable { private final Reader reader; - private final ObjectMapper om; - private final List locales; private final int databaseType; @@ -99,12 +95,6 @@ private DatabaseReader(Builder builder) throws IOException { throw new IllegalArgumentException( "Unsupported Builder configuration: expected either File or URL"); } - this.om = new ObjectMapper(); - this.om.configure(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS, false); - this.om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, - false); - this.om.configure( - DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true); this.locales = builder.locales; databaseType = getDatabaseType(); @@ -227,70 +217,54 @@ public DatabaseReader build() throws IOException { } } - /** - * @param ipAddress IPv4 or IPv6 address to lookup. - * @param cls The class to deserialize to. - * @param expectedType The expected database type. - * @return A object with the data for the IP address - * @throws IOException if there is an error opening or reading from the file. - * @throws AddressNotFoundException if the IP address is not in our database - */ - private T getOrThrowException(InetAddress ipAddress, Class cls, - DatabaseType expectedType) throws IOException, AddressNotFoundException { - Optional t = get(ipAddress, cls, expectedType, 1); - if (!t.isPresent()) { - throw new AddressNotFoundException("The address " - + ipAddress.getHostAddress() + " is not in the database."); + static final class LookupResult { + final T model; + final String ipAddress; + final Network network; + + LookupResult(T model, String ipAddress, Network network) { + this.model = model; + this.ipAddress = ipAddress; + this.network = network; + } + + T getModel() { + return this.model; + } + + String getIpAddress() { + return this.ipAddress; } - return t.get(); + Network getNetwork() { + return this.network; + } } /** * @param ipAddress IPv4 or IPv6 address to lookup. * @param cls The class to deserialize to. * @param expectedType The expected database type. - * @param stackDepth Used to work out how far down the stack we should look, for the method name - * we should use to report back to the user when in error. If this is called directly from the - * method to report to the use set to zero, if this is called indirectly then it is the number of - * methods between this method and the method to report the name of. - * @return A object with the data for the IP address or null if the IP address is not in our database + * @return A LookupResult object with the data for the IP address * @throws IOException if there is an error opening or reading from the file. */ - private Optional get(InetAddress ipAddress, Class cls, - DatabaseType expectedType, int stackDepth) throws IOException, AddressNotFoundException { + private LookupResult get(InetAddress ipAddress, Class cls, + DatabaseType expectedType) + throws IOException, AddressNotFoundException { if ((databaseType & expectedType.type) == 0) { - String caller = Thread.currentThread().getStackTrace()[2 + stackDepth] + String caller = Thread.currentThread().getStackTrace()[3] .getMethodName(); throw new UnsupportedOperationException( "Invalid attempt to open a " + getMetadata().getDatabaseType() + " database using the " + caller + " method"); } - // We are using the fully qualified name as otherwise it is ambiguous - // on Java 14 due to the new java.lang.Record. - com.maxmind.db.Record record = reader.getRecord(ipAddress); - - ObjectNode node = jsonNodeToObjectNode(record.getData()); + DatabaseRecord record = reader.getRecord(ipAddress, cls); - if (node == null) { - return Optional.empty(); - } - - InjectableValues inject = new JsonInjector(locales, ipAddress.getHostAddress(), record.getNetwork()); + T o = record.getData(); - return Optional.of(this.om.reader(inject).treeToValue(node, cls)); - } - - - private ObjectNode jsonNodeToObjectNode(JsonNode node) - throws InvalidDatabaseException { - if (node == null || node instanceof ObjectNode) { - return (ObjectNode) node; - } - throw new InvalidDatabaseException( - "Unexpected data type returned. The GeoIP2 database may be corrupt."); + return new LookupResult<>(o, ipAddress.getHostAddress(), record.getNetwork()); } /** @@ -315,25 +289,79 @@ public void close() throws IOException { @Override public CountryResponse country(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this.getOrThrowException(ipAddress, CountryResponse.class, DatabaseType.COUNTRY); + Optional r = getCountry(ipAddress); + if (!r.isPresent()) { + throw new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database."); + } + return r.get(); } @Override public Optional tryCountry(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this.get(ipAddress, CountryResponse.class, DatabaseType.COUNTRY, 0); + return getCountry(ipAddress); + } + + private Optional getCountry( + InetAddress ipAddress + ) throws IOException, GeoIp2Exception { + LookupResult result = this.get( + ipAddress, + CountryResponse.class, + DatabaseType.COUNTRY + ); + CountryResponse response = result.getModel(); + if (response == null) { + return Optional.empty(); + } + return Optional.of( + new CountryResponse( + response, + result.getIpAddress(), + result.getNetwork(), + locales + ) + ); } @Override public CityResponse city(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this.getOrThrowException(ipAddress, CityResponse.class, DatabaseType.CITY); + Optional r = getCity(ipAddress); + if (!r.isPresent()) { + throw new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database."); + } + return r.get(); } @Override public Optional tryCity(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this.get(ipAddress, CityResponse.class, DatabaseType.CITY, 0); + return getCity(ipAddress); + } + + private Optional getCity( + InetAddress ipAddress + ) throws IOException, GeoIp2Exception { + LookupResult result = this.get( + ipAddress, + CityResponse.class, + DatabaseType.CITY + ); + CityResponse response = result.getModel(); + if (response == null) { + return Optional.empty(); + } + return Optional.of( + new CityResponse( + response, + result.getIpAddress(), + result.getNetwork(), + locales + ) + ); } /** @@ -347,13 +375,39 @@ public Optional tryCity(InetAddress ipAddress) throws IOException, @Override public AnonymousIpResponse anonymousIp(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this.getOrThrowException(ipAddress, AnonymousIpResponse.class, DatabaseType.ANONYMOUS_IP); + Optional r = getAnonymousIp(ipAddress); + if (!r.isPresent()) { + throw new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database."); + } + return r.get(); } @Override public Optional tryAnonymousIp(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this.get(ipAddress, AnonymousIpResponse.class, DatabaseType.ANONYMOUS_IP, 0); + return getAnonymousIp(ipAddress); + } + + private Optional getAnonymousIp( + InetAddress ipAddress + ) throws IOException, GeoIp2Exception { + LookupResult result = this.get( + ipAddress, + AnonymousIpResponse.class, + DatabaseType.ANONYMOUS_IP + ); + AnonymousIpResponse response = result.getModel(); + if (response == null) { + return Optional.empty(); + } + return Optional.of( + new AnonymousIpResponse( + response, + result.getIpAddress(), + result.getNetwork() + ) + ); } /** @@ -367,13 +421,38 @@ public Optional tryAnonymousIp(InetAddress ipAddress) throw @Override public AsnResponse asn(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this.getOrThrowException(ipAddress, AsnResponse.class, DatabaseType.ASN); + Optional r = getAsn(ipAddress); + if (!r.isPresent()) { + throw new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database."); + } + return r.get(); } @Override public Optional tryAsn(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this.get(ipAddress, AsnResponse.class, DatabaseType.ASN, 0); + return getAsn(ipAddress); + } + + private Optional getAsn(InetAddress ipAddress) + throws IOException, GeoIp2Exception { + LookupResult result = this.get( + ipAddress, + AsnResponse.class, + DatabaseType.ASN + ); + AsnResponse response = result.getModel(); + if (response == null) { + return Optional.empty(); + } + return Optional.of( + new AsnResponse( + response, + result.getIpAddress(), + result.getNetwork() + ) + ); } /** @@ -387,15 +466,39 @@ public Optional tryAsn(InetAddress ipAddress) throws IOException, @Override public ConnectionTypeResponse connectionType(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this.getOrThrowException(ipAddress, ConnectionTypeResponse.class, - DatabaseType.CONNECTION_TYPE); + Optional r = getConnectionType(ipAddress); + if (!r.isPresent()) { + throw new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database."); + } + return r.get(); } @Override public Optional tryConnectionType(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this.get(ipAddress, ConnectionTypeResponse.class, - DatabaseType.CONNECTION_TYPE, 0); + return getConnectionType(ipAddress); + } + + private Optional getConnectionType( + InetAddress ipAddress + ) throws IOException, GeoIp2Exception { + LookupResult result = this.get( + ipAddress, + ConnectionTypeResponse.class, + DatabaseType.CONNECTION_TYPE + ); + ConnectionTypeResponse response = result.getModel(); + if (response == null) { + return Optional.empty(); + } + return Optional.of( + new ConnectionTypeResponse( + response, + result.getIpAddress(), + result.getNetwork() + ) + ); } /** @@ -409,15 +512,39 @@ public Optional tryConnectionType(InetAddress ipAddress) @Override public DomainResponse domain(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this - .getOrThrowException(ipAddress, DomainResponse.class, DatabaseType.DOMAIN); + Optional r = getDomain(ipAddress); + if (!r.isPresent()) { + throw new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database."); + } + return r.get(); } @Override public Optional tryDomain(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this - .get(ipAddress, DomainResponse.class, DatabaseType.DOMAIN, 0); + return getDomain(ipAddress); + } + + private Optional getDomain( + InetAddress ipAddress + ) throws IOException, GeoIp2Exception { + LookupResult result = this.get( + ipAddress, + DomainResponse.class, + DatabaseType.DOMAIN + ); + DomainResponse response = result.getModel(); + if (response == null) { + return Optional.empty(); + } + return Optional.of( + new DomainResponse( + response, + result.getIpAddress(), + result.getNetwork() + ) + ); } /** @@ -431,15 +558,41 @@ public Optional tryDomain(InetAddress ipAddress) throws IOExcept @Override public EnterpriseResponse enterprise(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this.getOrThrowException(ipAddress, EnterpriseResponse.class, DatabaseType.ENTERPRISE); + Optional r = getEnterprise(ipAddress); + if (!r.isPresent()) { + throw new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database."); + } + return r.get(); } @Override public Optional tryEnterprise(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this.get(ipAddress, EnterpriseResponse.class, DatabaseType.ENTERPRISE, 0); + return getEnterprise(ipAddress); } + private Optional getEnterprise( + InetAddress ipAddress + ) throws IOException, GeoIp2Exception { + LookupResult result = this.get( + ipAddress, + EnterpriseResponse.class, + DatabaseType.ENTERPRISE + ); + EnterpriseResponse response = result.getModel(); + if (response == null) { + return Optional.empty(); + } + return Optional.of( + new EnterpriseResponse( + response, + result.getIpAddress(), + result.getNetwork(), + locales + ) + ); + } /** * Look up an IP address in a GeoIP2 ISP database. @@ -452,13 +605,39 @@ public Optional tryEnterprise(InetAddress ipAddress) throws @Override public IspResponse isp(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this.getOrThrowException(ipAddress, IspResponse.class, DatabaseType.ISP); + Optional r = getIsp(ipAddress); + if (!r.isPresent()) { + throw new AddressNotFoundException("The address " + + ipAddress.getHostAddress() + " is not in the database."); + } + return r.get(); } @Override public Optional tryIsp(InetAddress ipAddress) throws IOException, GeoIp2Exception { - return this.get(ipAddress, IspResponse.class, DatabaseType.ISP, 0); + return getIsp(ipAddress); + } + + private Optional getIsp( + InetAddress ipAddress + ) throws IOException, GeoIp2Exception { + LookupResult result = this.get( + ipAddress, + IspResponse.class, + DatabaseType.ISP + ); + IspResponse response = result.getModel(); + if (response == null) { + return Optional.empty(); + } + return Optional.of( + new IspResponse( + response, + result.getIpAddress(), + result.getNetwork() + ) + ); } /** diff --git a/src/main/java/com/maxmind/geoip2/model/AbstractCityResponse.java b/src/main/java/com/maxmind/geoip2/model/AbstractCityResponse.java index 8782e3f4..8ea76544 100644 --- a/src/main/java/com/maxmind/geoip2/model/AbstractCityResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/AbstractCityResponse.java @@ -1,6 +1,7 @@ package com.maxmind.geoip2.model; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.maxmind.db.Network; import com.maxmind.geoip2.record.*; import java.util.ArrayList; @@ -36,6 +37,32 @@ public abstract class AbstractCityResponse extends AbstractCountryResponse { 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. */ diff --git a/src/main/java/com/maxmind/geoip2/model/AbstractCountryResponse.java b/src/main/java/com/maxmind/geoip2/model/AbstractCountryResponse.java index 57977f24..727740b0 100644 --- a/src/main/java/com/maxmind/geoip2/model/AbstractCountryResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/AbstractCountryResponse.java @@ -1,8 +1,11 @@ package com.maxmind.geoip2.model; import com.fasterxml.jackson.annotation.JsonProperty; +import com.maxmind.db.Network; import com.maxmind.geoip2.record.*; +import java.util.List; + public abstract class AbstractCountryResponse extends AbstractResponse { private final Continent continent; @@ -32,6 +35,22 @@ public abstract class AbstractCountryResponse extends AbstractResponse { 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. */ diff --git a/src/main/java/com/maxmind/geoip2/model/AnonymousIpResponse.java b/src/main/java/com/maxmind/geoip2/model/AnonymousIpResponse.java index 3b81f4e0..c06976a9 100644 --- a/src/main/java/com/maxmind/geoip2/model/AnonymousIpResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/AnonymousIpResponse.java @@ -5,6 +5,8 @@ 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.MaxMindDbParameter; import com.maxmind.db.Network; import com.maxmind.geoip2.NetworkDeserializer; @@ -55,6 +57,43 @@ public AnonymousIpResponse( this.network = network; } + @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_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, + isTorExitNode != null ? isTorExitNode : false, + network + ); + } + + public AnonymousIpResponse( + AnonymousIpResponse response, + String ipAddress, + Network network + ) { + this( + ipAddress, + response.isAnonymous(), + response.isAnonymousVpn(), + response.isHostingProvider(), + response.isPublicProxy(), + response.isTorExitNode(), + network + ); + } + /** * @return whether the IP address belongs to any sort of anonymous network. */ @@ -118,4 +157,4 @@ public String getIpAddress() { public Network getNetwork() { return this.network; } -} \ No newline at end of file +} diff --git a/src/main/java/com/maxmind/geoip2/model/AsnResponse.java b/src/main/java/com/maxmind/geoip2/model/AsnResponse.java index 22eb7ce5..5c55af42 100644 --- a/src/main/java/com/maxmind/geoip2/model/AsnResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/AsnResponse.java @@ -5,6 +5,8 @@ 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.MaxMindDbParameter; import com.maxmind.db.Network; import com.maxmind.geoip2.NetworkDeserializer; @@ -19,7 +21,7 @@ public class AsnResponse extends AbstractResponse { private final Network network; AsnResponse() { - this(null, null, null); + this((Integer) null, null, null, null); } public AsnResponse( @@ -42,6 +44,32 @@ public AsnResponse( this.network = network; } + @MaxMindDbConstructor + public AsnResponse( + @MaxMindDbParameter(name="autonomous_system_number") Long autonomousSystemNumber, + @MaxMindDbParameter(name="autonomous_system_organization") String autonomousSystemOrganization, + @MaxMindDbParameter(name="ip_address") String ipAddress, + @MaxMindDbParameter(name="network") Network network + ) { + this.autonomousSystemNumber = autonomousSystemNumber != null ? autonomousSystemNumber.intValue() : null; + this.autonomousSystemOrganization = autonomousSystemOrganization; + this.ipAddress = ipAddress; + this.network = network; + } + + public AsnResponse( + AsnResponse response, + String ipAddress, + Network network + ) { + this( + response.getAutonomousSystemNumber(), + response.getAutonomousSystemOrganization(), + ipAddress, + network + ); + } + /** * @return The autonomous system number associated with the IP address. */ diff --git a/src/main/java/com/maxmind/geoip2/model/CityResponse.java b/src/main/java/com/maxmind/geoip2/model/CityResponse.java index 2ad5409b..002d3499 100644 --- a/src/main/java/com/maxmind/geoip2/model/CityResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/CityResponse.java @@ -2,9 +2,13 @@ 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.record.*; import java.util.ArrayList; +import java.util.List; /** *

@@ -27,19 +31,29 @@ public final class CityResponse extends AbstractCityResponse { this(null, null, null, null, null, null, null, null, null, null); } + @MaxMindDbConstructor public CityResponse( - @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") ArrayList subdivisions, - @JacksonInject("traits") @JsonProperty("traits") Traits traits + @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, + @JacksonInject("traits") @JsonProperty("traits") @MaxMindDbParameter(name="traits") Traits traits ) { super(city, continent, country, location, maxmind, postal, registeredCountry, representedCountry, subdivisions, traits); } + + public CityResponse( + CityResponse response, + String ipAddress, + Network network, + List locales + ) { + super(response, ipAddress, network, locales); + } } diff --git a/src/main/java/com/maxmind/geoip2/model/ConnectionTypeResponse.java b/src/main/java/com/maxmind/geoip2/model/ConnectionTypeResponse.java index 6609311d..b39cd9c8 100644 --- a/src/main/java/com/maxmind/geoip2/model/ConnectionTypeResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/ConnectionTypeResponse.java @@ -6,6 +6,8 @@ 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.MaxMindDbParameter; import com.maxmind.db.Network; import com.maxmind.geoip2.NetworkDeserializer; @@ -37,6 +39,25 @@ public enum ConnectionType { public String toString() { return this.name; } + + public static ConnectionType fromString(String s) { + if (s == null) { + return null; + } + + switch (s) { + case "Dialup": + return ConnectionType.DIALUP; + case "Cable/DSL": + return ConnectionType.CABLE_DSL; + case "Corporate": + return ConnectionType.CORPORATE; + case "Cellular": + return ConnectionType.CELLULAR; + default: + return null; + } + } } private final ConnectionType connectionType; @@ -64,6 +85,31 @@ public ConnectionTypeResponse( this.network = network; } + @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 + ); + } + + public ConnectionTypeResponse( + ConnectionTypeResponse response, + String ipAddress, + Network network + ) { + this( + response.getConnectionType(), + ipAddress, + network + ); + } + /** * @return The connection type of the IP address. */ diff --git a/src/main/java/com/maxmind/geoip2/model/CountryResponse.java b/src/main/java/com/maxmind/geoip2/model/CountryResponse.java index f45efd10..3b43042f 100644 --- a/src/main/java/com/maxmind/geoip2/model/CountryResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/CountryResponse.java @@ -2,8 +2,14 @@ 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.record.*; +import java.net.InetAddress; +import java.util.List; + /** * This class provides a model for the data returned by the GeoIP2 Precision: * Country end point. @@ -17,14 +23,24 @@ public final class CountryResponse extends AbstractCountryResponse { this(null, null, null, null, null, null); } + @MaxMindDbConstructor public CountryResponse( - @JsonProperty("continent") Continent continent, - @JsonProperty("country") Country country, - @JsonProperty("maxmind") MaxMind maxmind, - @JsonProperty("registered_country") Country registeredCountry, - @JsonProperty("represented_country") RepresentedCountry representedCountry, - @JacksonInject("traits") @JsonProperty("traits") Traits traits + @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, + @JacksonInject("traits") @JsonProperty("traits") @MaxMindDbParameter(name="traits") Traits traits ) { super(continent, country, maxmind, registeredCountry, representedCountry, traits); } + + public CountryResponse( + CountryResponse response, + String ipAddress, + Network network, + List locales + ) { + super(response, ipAddress, network, locales); + } } diff --git a/src/main/java/com/maxmind/geoip2/model/DomainResponse.java b/src/main/java/com/maxmind/geoip2/model/DomainResponse.java index 489354dd..0e7f4fe7 100644 --- a/src/main/java/com/maxmind/geoip2/model/DomainResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/DomainResponse.java @@ -5,6 +5,8 @@ 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.MaxMindDbParameter; import com.maxmind.db.Network; import com.maxmind.geoip2.NetworkDeserializer; @@ -28,16 +30,25 @@ public DomainResponse( this(domain, ipAddress, null); } + @MaxMindDbConstructor public DomainResponse( - @JsonProperty("domain") String domain, - @JacksonInject("ip_address") @JsonProperty("ip_address") String ipAddress, - @JacksonInject("network") @JsonProperty("network") @JsonDeserialize(using = NetworkDeserializer.class) Network network + @JsonProperty("domain") @MaxMindDbParameter(name="domain") String domain, + @JacksonInject("ip_address") @JsonProperty("ip_address") @MaxMindDbParameter(name="ip_address") String ipAddress, + @JacksonInject("network") @JsonProperty("network") @JsonDeserialize(using = NetworkDeserializer.class) @MaxMindDbParameter(name="network") Network network ) { this.domain = domain; this.ipAddress = ipAddress; this.network = network; } + public DomainResponse( + DomainResponse response, + String ipAddress, + Network network + ) { + this(response.getDomain(), ipAddress, network); + } + /** * @return the The second level domain associated with the IP address. This * will be something like "example.com" or "example.co.uk", not diff --git a/src/main/java/com/maxmind/geoip2/model/EnterpriseResponse.java b/src/main/java/com/maxmind/geoip2/model/EnterpriseResponse.java index bad4104f..67eb21c4 100644 --- a/src/main/java/com/maxmind/geoip2/model/EnterpriseResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/EnterpriseResponse.java @@ -2,9 +2,13 @@ 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.record.*; import java.util.ArrayList; +import java.util.List; /** *

@@ -14,19 +18,29 @@ */ public final class EnterpriseResponse extends AbstractCityResponse { + @MaxMindDbConstructor public EnterpriseResponse( - @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") ArrayList subdivisions, - @JacksonInject("traits") @JsonProperty("traits") Traits traits + @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, + @JacksonInject("traits") @JsonProperty("traits") @MaxMindDbParameter(name="traits") Traits traits ) { super(city, continent, country, location, maxmind, postal, registeredCountry, representedCountry, subdivisions, traits); } + + public EnterpriseResponse( + EnterpriseResponse response, + String ipAddress, + Network network, + List locales + ) { + super(response, ipAddress, network, locales); + } } diff --git a/src/main/java/com/maxmind/geoip2/model/IspResponse.java b/src/main/java/com/maxmind/geoip2/model/IspResponse.java index 5de2c38a..c244801e 100644 --- a/src/main/java/com/maxmind/geoip2/model/IspResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/IspResponse.java @@ -3,6 +3,8 @@ 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.maxmind.db.MaxMindDbParameter; import com.maxmind.db.Network; import com.maxmind.geoip2.NetworkDeserializer; @@ -41,6 +43,40 @@ public IspResponse( this.organization = organization; } + @MaxMindDbConstructor + public IspResponse( + @MaxMindDbParameter(name="autonomous_system_number") Long autonomousSystemNumber, + @MaxMindDbParameter(name="autonomous_system_organization") String autonomousSystemOrganization, + @MaxMindDbParameter(name="ip_address") String ipAddress, + @MaxMindDbParameter(name="isp") String isp, + @MaxMindDbParameter(name="organization") String organization, + @MaxMindDbParameter(name="network") Network network + ) { + this( + autonomousSystemNumber != null ? autonomousSystemNumber.intValue() : null, + autonomousSystemOrganization, + ipAddress, + isp, + organization, + network + ); + } + + public IspResponse( + IspResponse response, + String ipAddress, + Network network + ) { + this( + response.getAutonomousSystemNumber(), + response.getAutonomousSystemOrganization(), + ipAddress, + response.getIsp(), + response.getOrganization(), + network + ); + } + /** * @return The name of the ISP associated with the IP address. */ diff --git a/src/main/java/com/maxmind/geoip2/record/City.java b/src/main/java/com/maxmind/geoip2/record/City.java index 00ddff6d..ceb4c1eb 100644 --- a/src/main/java/com/maxmind/geoip2/record/City.java +++ b/src/main/java/com/maxmind/geoip2/record/City.java @@ -2,6 +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 java.util.List; import java.util.Map; @@ -23,7 +25,7 @@ public final class City extends AbstractNamedRecord { private final Integer confidence; public City() { - this(null, null, null, null); + this(null, null, (Integer) null, null); } public City( @@ -36,6 +38,33 @@ public City( this.confidence = confidence; } + @MaxMindDbConstructor + public City( + @MaxMindDbParameter(name="locales") List locales, + @MaxMindDbParameter(name="confidence") Integer confidence, + @MaxMindDbParameter(name="geoname_id") Long geoNameId, + @MaxMindDbParameter(name="names") Map names + ) { + this( + locales, + confidence, + geoNameId != null ? geoNameId.intValue() : null, + names + ); + } + + public City( + City city, + List locales + ) { + this( + locales, + city.getConfidence(), + city.getGeoNameId(), + city.getNames() + ); + } + /** * @return A value from 0-100 indicating MaxMind's confidence that the city * is correct. This attribute is only available from the Insights diff --git a/src/main/java/com/maxmind/geoip2/record/Continent.java b/src/main/java/com/maxmind/geoip2/record/Continent.java index 9aaecae3..5d207959 100644 --- a/src/main/java/com/maxmind/geoip2/record/Continent.java +++ b/src/main/java/com/maxmind/geoip2/record/Continent.java @@ -2,6 +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 java.util.List; import java.util.Map; @@ -23,7 +25,7 @@ public final class Continent extends AbstractNamedRecord { private final String code; public Continent() { - this(null, null, null, null); + this(null, null, (Integer) null, null); } public Continent( @@ -36,6 +38,33 @@ public Continent( this.code = code; } + @MaxMindDbConstructor + public Continent( + @MaxMindDbParameter(name="locales") List locales, + @MaxMindDbParameter(name="code") String code, + @MaxMindDbParameter(name="geoname_id") Long geoNameId, + @MaxMindDbParameter(name="names") Map names + ) { + this( + locales, + code, + geoNameId != null ? geoNameId.intValue() : null, + names + ); + } + + public Continent( + Continent continent, + List locales + ) { + this( + locales, + continent.getCode(), + continent.getGeoNameId(), + continent.getNames() + ); + } + /** * @return A two character continent code like "NA" (North America) or "OC" * (Oceania). This attribute is returned by all end points. diff --git a/src/main/java/com/maxmind/geoip2/record/Country.java b/src/main/java/com/maxmind/geoip2/record/Country.java index 42126c22..dacf09b8 100644 --- a/src/main/java/com/maxmind/geoip2/record/Country.java +++ b/src/main/java/com/maxmind/geoip2/record/Country.java @@ -2,6 +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 java.util.List; import java.util.Map; @@ -25,7 +27,7 @@ public class Country extends AbstractNamedRecord { private final String isoCode; public Country() { - this(null, null, null, false, null, null); + this(null, null, (Integer) null, false, null, null); } // This method is for backwards compatibility. We should remove it when we @@ -54,6 +56,39 @@ public Country( this.isoCode = isoCode; } + @MaxMindDbConstructor + public Country( + @MaxMindDbParameter(name="locales") List locales, + @MaxMindDbParameter(name="confidence") Integer confidence, + @MaxMindDbParameter(name="geoname_id") Long geoNameId, + @MaxMindDbParameter(name="is_in_european_union") Boolean isInEuropeanUnion, + @MaxMindDbParameter(name="iso_code") String isoCode, + @MaxMindDbParameter(name="names") Map names + ) { + this( + locales, + confidence, + geoNameId != null ? geoNameId.intValue() : null, + isInEuropeanUnion != null ? isInEuropeanUnion : false, + isoCode, + names + ); + } + + public Country( + Country country, + List locales + ) { + this( + locales, + country.getConfidence(), + country.getGeoNameId(), + country.isInEuropeanUnion(), + country.getIsoCode(), + country.getNames() + ); + } + /** * @return A value from 0-100 indicating MaxMind's confidence that the * country is correct. This attribute is only available from the diff --git a/src/main/java/com/maxmind/geoip2/record/Location.java b/src/main/java/com/maxmind/geoip2/record/Location.java index 397c429c..ac77dc68 100644 --- a/src/main/java/com/maxmind/geoip2/record/Location.java +++ b/src/main/java/com/maxmind/geoip2/record/Location.java @@ -1,6 +1,8 @@ package com.maxmind.geoip2.record; import com.fasterxml.jackson.annotation.JsonProperty; +import com.maxmind.db.MaxMindDbConstructor; +import com.maxmind.db.MaxMindDbParameter; /** *

@@ -21,14 +23,15 @@ public Location() { this(null, null, null, null, null, null, null); } + @MaxMindDbConstructor public Location( - @JsonProperty("accuracy_radius") Integer accuracyRadius, - @JsonProperty("average_income") Integer averageIncome, - @JsonProperty("latitude") Double latitude, - @JsonProperty("longitude") Double longitude, - @JsonProperty("metro_code") Integer metroCode, - @JsonProperty("population_density") Integer populationDensity, - @JsonProperty("time_zone") String timeZone + @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("metro_code") @MaxMindDbParameter(name="metro_code") Integer metroCode, + @JsonProperty("population_density") @MaxMindDbParameter(name="population_density") Integer populationDensity, + @JsonProperty("time_zone") @MaxMindDbParameter(name="time_zone") String timeZone ) { this.accuracyRadius = accuracyRadius; this.averageIncome = averageIncome; diff --git a/src/main/java/com/maxmind/geoip2/record/MaxMind.java b/src/main/java/com/maxmind/geoip2/record/MaxMind.java index 2473b608..62e914e7 100644 --- a/src/main/java/com/maxmind/geoip2/record/MaxMind.java +++ b/src/main/java/com/maxmind/geoip2/record/MaxMind.java @@ -1,6 +1,8 @@ package com.maxmind.geoip2.record; import com.fasterxml.jackson.annotation.JsonProperty; +import com.maxmind.db.MaxMindDbConstructor; +import com.maxmind.db.MaxMindDbParameter; /** *

@@ -18,7 +20,8 @@ public MaxMind() { this(null); } - public MaxMind(@JsonProperty("queries_remaining") Integer queriesRemaining) { + @MaxMindDbConstructor + public MaxMind(@JsonProperty("queries_remaining") @MaxMindDbParameter(name="queries_remaining") Integer queriesRemaining) { this.queriesRemaining = queriesRemaining; } diff --git a/src/main/java/com/maxmind/geoip2/record/Postal.java b/src/main/java/com/maxmind/geoip2/record/Postal.java index 577c30b5..b455aee4 100644 --- a/src/main/java/com/maxmind/geoip2/record/Postal.java +++ b/src/main/java/com/maxmind/geoip2/record/Postal.java @@ -1,6 +1,8 @@ package com.maxmind.geoip2.record; import com.fasterxml.jackson.annotation.JsonProperty; +import com.maxmind.db.MaxMindDbConstructor; +import com.maxmind.db.MaxMindDbParameter; /** *

@@ -19,7 +21,11 @@ public Postal() { this(null, null); } - public Postal(@JsonProperty("code") String code, @JsonProperty("confidence") Integer confidence) { + @MaxMindDbConstructor + public Postal( + @JsonProperty("code") @MaxMindDbParameter(name="code") String code, + @JsonProperty("confidence") @MaxMindDbParameter(name="confidence") Integer confidence + ) { this.code = code; this.confidence = confidence; } diff --git a/src/main/java/com/maxmind/geoip2/record/RepresentedCountry.java b/src/main/java/com/maxmind/geoip2/record/RepresentedCountry.java index c6147bd9..e832a61e 100644 --- a/src/main/java/com/maxmind/geoip2/record/RepresentedCountry.java +++ b/src/main/java/com/maxmind/geoip2/record/RepresentedCountry.java @@ -2,6 +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 java.util.List; import java.util.Map; @@ -25,7 +27,7 @@ public final class RepresentedCountry extends Country { private final String type; public RepresentedCountry() { - this(null, null, null, false, null, null, null); + this(null, null, (Integer) null, false, null, null, null); } // This method is for backwards compatibility. We should remove it when we @@ -55,6 +57,42 @@ public RepresentedCountry( this.type = type; } + @MaxMindDbConstructor + public RepresentedCountry( + @MaxMindDbParameter(name="locales") List locales, + @MaxMindDbParameter(name="confidence") Integer confidence, + @MaxMindDbParameter(name="geoname_id") Long geoNameId, + @MaxMindDbParameter(name="is_in_european_union") Boolean isInEuropeanUnion, + @MaxMindDbParameter(name="iso_code") String isoCode, + @MaxMindDbParameter(name="names") Map names, + @MaxMindDbParameter(name="type") String type + ) { + this( + locales, + confidence, + geoNameId != null ? geoNameId.intValue() : null, + isInEuropeanUnion != null ? isInEuropeanUnion : false, + isoCode, + names, + type + ); + } + + public RepresentedCountry( + RepresentedCountry country, + List locales + ) { + this( + locales, + country.getConfidence(), + country.getGeoNameId(), + country.isInEuropeanUnion(), + country.getIsoCode(), + country.getNames(), + country.getType() + ); + } + /** * @return A string indicating the type of entity that is representing the * country. Currently we only return {@code military} but this could diff --git a/src/main/java/com/maxmind/geoip2/record/Subdivision.java b/src/main/java/com/maxmind/geoip2/record/Subdivision.java index d4b71e61..2249b450 100644 --- a/src/main/java/com/maxmind/geoip2/record/Subdivision.java +++ b/src/main/java/com/maxmind/geoip2/record/Subdivision.java @@ -2,6 +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 java.util.List; import java.util.Map; @@ -24,7 +26,7 @@ public final class Subdivision extends AbstractNamedRecord { private final String isoCode; public Subdivision() { - this(null, null, null, null, null); + this(null, null, (Integer) null, null, null); } public Subdivision( @@ -39,6 +41,36 @@ public Subdivision( this.isoCode = isoCode; } + @MaxMindDbConstructor + public Subdivision( + @MaxMindDbParameter(name="locales") List locales, + @MaxMindDbParameter(name="confidence") Integer confidence, + @MaxMindDbParameter(name="geoname_id") Long geoNameId, + @MaxMindDbParameter(name="iso_code") String isoCode, + @MaxMindDbParameter(name="names") Map names + ) { + this( + locales, + confidence, + geoNameId != null ? geoNameId.intValue() : null, + isoCode, + names + ); + } + + public Subdivision( + Subdivision subdivision, + List locales + ) { + this( + locales, + subdivision.getConfidence(), + subdivision.getGeoNameId(), + subdivision.getIsoCode(), + subdivision.getNames() + ); + } + /** * @return This is a value from 0-100 indicating MaxMind's confidence that * the subdivision is correct. This attribute is only available from diff --git a/src/main/java/com/maxmind/geoip2/record/Traits.java b/src/main/java/com/maxmind/geoip2/record/Traits.java index afef58b9..9558ce77 100644 --- a/src/main/java/com/maxmind/geoip2/record/Traits.java +++ b/src/main/java/com/maxmind/geoip2/record/Traits.java @@ -5,6 +5,8 @@ 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.MaxMindDbParameter; import com.maxmind.db.Network; import com.maxmind.geoip2.NetworkDeserializer; import com.maxmind.geoip2.model.ConnectionTypeResponse.ConnectionType; @@ -48,7 +50,7 @@ public Traits(String ipAddress) { } public Traits(String ipAddress, Network network) { - this(null, null, null, null, + this((Integer) null, null, null, null, ipAddress, false, false, false, false, false, false, false, false, null, network, null, null, null, null); @@ -160,6 +162,79 @@ public Traits( this.staticIpScore = staticIpScore; } + @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_proxy") Boolean isAnonymousProxy, + @MaxMindDbParameter(name="is_anonymous_vpn") Boolean isAnonymousVpn, + @MaxMindDbParameter(name="is_hosting_provider") Boolean isHostingProvider, + @MaxMindDbParameter(name="is_legitimate_proxy") Boolean isLegitimateProxy, + @MaxMindDbParameter(name="is_public_proxy") Boolean isPublicProxy, + @MaxMindDbParameter(name="is_satellite_provider") Boolean isSatelliteProvider, + @MaxMindDbParameter(name="is_tor_exit_node") Boolean isTorExitNode, + @MaxMindDbParameter(name="isp") String isp, + @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 != null ? autonomousSystemNumber.intValue() : null, + autonomousSystemOrganization, + ConnectionType.fromString(connectionType), + domain, + ipAddress, + isAnonymous != null ? isAnonymous : false, + isAnonymousProxy != null ? isAnonymousProxy : false, + isAnonymousVpn != null ? isAnonymousVpn : false, + isHostingProvider != null ? isHostingProvider : false, + isLegitimateProxy != null ? isLegitimateProxy : false, + isPublicProxy != null ? isPublicProxy : false, + isSatelliteProvider != null ? isSatelliteProvider : false, + isTorExitNode != null ? isTorExitNode : false, + isp, + network, + organization, + userType, + userCount, + staticIpScore + ); + } + + public Traits( + Traits traits, + String ipAddress, + Network network + ) { + this( + traits.getAutonomousSystemNumber(), + traits.getAutonomousSystemOrganization(), + traits.getConnectionType(), + traits.getDomain(), + ipAddress, + traits.isAnonymous(), + traits.isAnonymousProxy(), + traits.isAnonymousVpn(), + traits.isHostingProvider(), + traits.isLegitimateProxy(), + traits.isPublicProxy(), + traits.isSatelliteProvider(), + traits.isTorExitNode(), + traits.getIsp(), + network, + traits.getOrganization(), + traits.getUserType(), + traits.getUserCount(), + traits.getStaticIpScore() + ); + } + /** * @return The