9 | * Contains data related to your MaxMind account.
10 | *
11 | *
12 | * @param queriesRemaining The number of remaining queries in your account for the current
13 | * web service. This returns {@code null} when called on a database.
14 | */
15 | public record MaxMind(
16 | @JsonProperty("queries_remaining")
17 | @MaxMindDbParameter(name = "queries_remaining")
18 | Integer queriesRemaining
19 | ) implements JsonSerializable {
20 |
21 | /**
22 | * Constructs a {@code MaxMind} record.
23 | */
24 | public MaxMind() {
25 | this(null);
26 | }
27 |
28 | /**
29 | * @return The number of remaining queries in your account for the current
30 | * web service. This returns {@code null} when called on a database.
31 | * @deprecated Use {@link #queriesRemaining()} instead. This method will be removed in 6.0.0.
32 | */
33 | @Deprecated(since = "5.0.0", forRemoval = true)
34 | @JsonProperty("queries_remaining")
35 | public Integer getQueriesRemaining() {
36 | return queriesRemaining();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/JsonSerializable.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import com.fasterxml.jackson.databind.MapperFeature;
5 | import com.fasterxml.jackson.databind.SerializationFeature;
6 | import com.fasterxml.jackson.databind.json.JsonMapper;
7 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
8 | import java.io.IOException;
9 |
10 | /**
11 | * Interface for classes that can be serialized to JSON.
12 | * Provides default implementation for toJson() method.
13 | */
14 | public interface JsonSerializable {
15 |
16 | /**
17 | * @return JSON representation of this object. The structure is the same as
18 | * the JSON provided by the GeoIP2 web service.
19 | * @throws IOException if there is an error serializing the object to JSON.
20 | */
21 | default String toJson() throws IOException {
22 | JsonMapper mapper = JsonMapper.builder()
23 | .disable(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS)
24 | .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
25 | .addModule(new JavaTimeModule())
26 | .addModule(new InetAddressModule())
27 | .serializationInclusion(JsonInclude.Include.NON_NULL)
28 | .serializationInclusion(JsonInclude.Include.NON_EMPTY)
29 | .build();
30 |
31 | return mapper.writeValueAsString(this);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/NamedRecord.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnore;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | /**
9 | * Interface for record classes that have localized names and GeoName IDs.
10 | * Provides a default implementation for the name() method that returns the name
11 | * in the first available locale.
12 | */
13 | public interface NamedRecord extends JsonSerializable {
14 |
15 | /**
16 | * @return The GeoName ID for this location.
17 | */
18 | @JsonProperty("geoname_id")
19 | Long geonameId();
20 |
21 | /**
22 | * @return A {@link Map} from locale codes to the name in that locale.
23 | */
24 | @JsonProperty("names")
25 | Map names();
26 |
27 | /**
28 | * @return The list of locales to use for name lookups.
29 | */
30 | @JsonIgnore
31 | List locales();
32 |
33 | /**
34 | * @return The name based on the locales list. Returns the name in the first
35 | * locale for which a name is available. If no name is available in any of the
36 | * specified locales, returns null.
37 | */
38 | @JsonIgnore
39 | default String name() {
40 | for (var lang : locales()) {
41 | if (names().containsKey(lang)) {
42 | return names().get(lang);
43 | }
44 | }
45 | return null;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/WebServiceProvider.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2;
2 |
3 | import com.maxmind.geoip2.exception.GeoIp2Exception;
4 | import com.maxmind.geoip2.model.CityResponse;
5 | import com.maxmind.geoip2.model.CountryResponse;
6 | import com.maxmind.geoip2.model.InsightsResponse;
7 | import java.io.IOException;
8 | import java.net.InetAddress;
9 |
10 | /**
11 | * Interface for GeoIP2 web service providers.
12 | */
13 | public interface WebServiceProvider extends GeoIp2Provider {
14 | /**
15 | * @return A Country model for the requesting IP address
16 | * @throws GeoIp2Exception if there is an error from the web service
17 | * @throws IOException if an IO error happens during the request
18 | */
19 | CountryResponse country() throws IOException, GeoIp2Exception;
20 |
21 | /**
22 | * @return A City model for the requesting IP address
23 | * @throws GeoIp2Exception if there is an error from the web service
24 | * @throws IOException if an IO error happens during the request
25 | */
26 | CityResponse city() throws IOException, GeoIp2Exception;
27 |
28 | /**
29 | * @return An Insights model for the requesting IP address
30 | * @throws GeoIp2Exception if there is an error from the web service
31 | * @throws IOException if an IO error happens during the request
32 | */
33 | InsightsResponse insights() throws IOException, GeoIp2Exception;
34 |
35 | /**
36 | * @param ipAddress IPv4 or IPv6 address to lookup.
37 | * @return An Insight model for the requested IP address.
38 | * @throws GeoIp2Exception if there is an error looking up the IP
39 | * @throws IOException if there is an IO error
40 | */
41 | InsightsResponse insights(InetAddress ipAddress) throws IOException,
42 | GeoIp2Exception;
43 | }
44 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | name: "Code scanning - action"
2 |
3 | on:
4 | push:
5 | branches-ignore:
6 | - 'dependabot/**'
7 | pull_request:
8 | schedule:
9 | - cron: '0 6 * * 3'
10 |
11 | jobs:
12 | CodeQL-Build:
13 |
14 | runs-on: ubuntu-latest
15 |
16 | permissions:
17 | security-events: write
18 |
19 | steps:
20 | - name: Checkout repository
21 | uses: actions/checkout@v6
22 | with:
23 | # We must fetch at least the immediate parents so that if this is
24 | # a pull request then we can checkout the head.
25 | fetch-depth: 2
26 | persist-credentials: false
27 |
28 | # If this run was triggered by a pull request event, then checkout
29 | # the head of the pull request instead of the merge commit.
30 | - run: git checkout HEAD^2
31 | if: ${{ github.event_name == 'pull_request' }}
32 |
33 | # Initializes the CodeQL tools for scanning.
34 | - name: Initialize CodeQL
35 | uses: github/codeql-action/init@v4
36 | # Override language selection by uncommenting this and choosing your languages
37 | # with:
38 | # languages: go, javascript, csharp, python, cpp, java
39 |
40 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
41 | # If this step fails, then you should remove it and run the build manually (see below)
42 | - name: Autobuild
43 | uses: github/codeql-action/autobuild@v4
44 |
45 | # ℹ️ Command-line programs to run using the OS shell.
46 | # 📚 https://git.io/JvXDl
47 |
48 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
49 | # and modify them (or add more) to build your code if your project
50 | # uses a compiled language
51 |
52 | #- run: |
53 | # make bootstrap
54 | # make release
55 |
56 | - name: Perform CodeQL Analysis
57 | uses: github/codeql-action/analyze@v4
58 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/record/Postal.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.record;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.maxmind.db.MaxMindDbParameter;
5 | import com.maxmind.geoip2.JsonSerializable;
6 |
7 | /**
8 | *
9 | * Contains data for the postal record associated with an IP address.
10 | *
11 | *
12 | * @param code The postal code of the location. Postal codes are not available for all
13 | * countries. In some countries, this will only contain part of the postal
14 | * code.
15 | * @param confidence A value from 0-100 indicating MaxMind's confidence that the postal
16 | * code is correct. This attribute is only available from the Insights
17 | * web service and the GeoIP2 Enterprise database.
18 | */
19 | public record Postal(
20 | @JsonProperty("code")
21 | @MaxMindDbParameter(name = "code")
22 | String code,
23 |
24 | @JsonProperty("confidence")
25 | @MaxMindDbParameter(name = "confidence")
26 | Integer confidence
27 | ) implements JsonSerializable {
28 |
29 | /**
30 | * Constructs a {@code Postal} record.
31 | */
32 | public Postal() {
33 | this(null, null);
34 | }
35 |
36 | /**
37 | * @return The postal code of the location. Postal codes are not available
38 | * for all countries. In some countries, this will only contain part
39 | * of the postal code.
40 | * @deprecated Use {@link #code()} instead. This method will be removed in 6.0.0.
41 | */
42 | @Deprecated(since = "5.0.0", forRemoval = true)
43 | public String getCode() {
44 | return code();
45 | }
46 |
47 | /**
48 | * @return A value from 0-100 indicating MaxMind's confidence that the
49 | * postal code is correct. This attribute is only available from the
50 | * Insights web service and the GeoIP2 Enterprise database.
51 | * @deprecated Use {@link #confidence()} instead. This method will be removed in 6.0.0.
52 | */
53 | @Deprecated(since = "5.0.0", forRemoval = true)
54 | public Integer getConfidence() {
55 | return confidence();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/exception/InvalidRequestException.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.exception;
2 |
3 | import java.net.URI;
4 |
5 | /**
6 | * This class represents a non-specific error returned by MaxMind's GeoIP2 web
7 | * service. This occurs when the web service is up and responding to requests,
8 | * but the request sent was invalid in some way.
9 | */
10 | public final class InvalidRequestException extends GeoIp2Exception {
11 | private final String code;
12 | private final URI uri;
13 |
14 | /**
15 | * @param message A message explaining the cause of the error.
16 | * @param code The error code returned by the web service.
17 | * @param uri The URI queried.
18 | */
19 | public InvalidRequestException(String message, String code, URI uri) {
20 | super(message);
21 | this.uri = uri;
22 | this.code = code;
23 | }
24 |
25 | /**
26 | * @param message A message explaining the cause of the error.
27 | * @param code The error code returned by the web service.
28 | * @param httpStatus The HTTP status of the response.
29 | * @param uri The URI queried.
30 | * @param e The cause of the exception.
31 | */
32 | public InvalidRequestException(String message, String code, int httpStatus,
33 | URI uri, Throwable e) {
34 | super(message, e);
35 | this.code = code;
36 | this.uri = uri;
37 | }
38 |
39 | /**
40 | * @return The error code returned by the MaxMind web service.
41 | */
42 | public String code() {
43 | return this.code;
44 | }
45 |
46 | /**
47 | * @return The error code returned by the MaxMind web service.
48 | * @deprecated Use {@link #code()} instead. This method will be removed in 6.0.0.
49 | */
50 | @Deprecated(since = "5.0.0", forRemoval = true)
51 | public String getCode() {
52 | return code();
53 | }
54 |
55 | /**
56 | * @return the URI queried.
57 | */
58 | public URI uri() {
59 | return this.uri;
60 | }
61 |
62 | /**
63 | * @return the URI queried.
64 | * @deprecated Use {@link #uri()} instead. This method will be removed in 6.0.0.
65 | */
66 | @Deprecated(since = "5.0.0", forRemoval = true)
67 | public URI getUri() {
68 | return uri();
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/exception/HttpException.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.exception;
2 |
3 | import java.io.IOException;
4 | import java.net.URI;
5 |
6 | /**
7 | * This class represents an HTTP transport error. This is not an error returned
8 | * by the web service itself. As such, it is a IOException instead of a
9 | * GeoIp2Exception.
10 | */
11 | public final class HttpException extends IOException {
12 | private final int httpStatus;
13 | private final URI uri;
14 |
15 | /**
16 | * @param message A message describing the reason why the exception was thrown.
17 | * @param httpStatus The HTTP status of the response that caused the exception.
18 | * @param uri The URI queried.
19 | */
20 | public HttpException(String message, int httpStatus, URI uri) {
21 | super(message);
22 | this.httpStatus = httpStatus;
23 | this.uri = uri;
24 | }
25 |
26 | /**
27 | * @param message A message describing the reason why the exception was thrown.
28 | * @param httpStatus The HTTP status of the response that caused the exception.
29 | * @param uri The URI queried.
30 | * @param cause The cause of the exception.
31 | */
32 | public HttpException(String message, int httpStatus, URI uri,
33 | Throwable cause) {
34 | super(message, cause);
35 | this.httpStatus = httpStatus;
36 | this.uri = uri;
37 | }
38 |
39 | /**
40 | * @return the HTTP status of the query that caused the exception.
41 | */
42 | public int httpStatus() {
43 | return this.httpStatus;
44 | }
45 |
46 | /**
47 | * @return the HTTP status of the query that caused the exception.
48 | * @deprecated Use {@link #httpStatus()} instead. This method will be removed in 6.0.0.
49 | */
50 | @Deprecated(since = "5.0.0", forRemoval = true)
51 | public int getHttpStatus() {
52 | return httpStatus();
53 | }
54 |
55 | /**
56 | * @return the URI queried.
57 | */
58 | public URI uri() {
59 | return this.uri;
60 | }
61 |
62 | /**
63 | * @return the URI queried.
64 | * @deprecated Use {@link #uri()} instead. This method will be removed in 6.0.0.
65 | */
66 | @Deprecated(since = "5.0.0", forRemoval = true)
67 | public URI getUri() {
68 | return uri();
69 | }
70 |
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/src/test/resources/test-data/insights0.json:
--------------------------------------------------------------------------------
1 | {
2 | "city": {
3 | "confidence": 76,
4 | "geoname_id": 9876,
5 | "names": {
6 | "en": "Minneapolis"
7 | }
8 | },
9 | "continent": {
10 | "code": "NA",
11 | "geoname_id": 42,
12 | "names": {
13 | "en": "North America"
14 | }
15 | },
16 | "country": {
17 | "confidence": 99,
18 | "geoname_id": 1,
19 | "iso_code": "US",
20 | "names": {
21 | "en": "United States of America"
22 | }
23 | },
24 | "location": {
25 | "accuracy_radius": 1500,
26 | "average_income": 24626,
27 | "latitude": 44.98,
28 | "longitude": 93.2636,
29 | "population_density": 1341,
30 | "time_zone": "America/Chicago"
31 | },
32 | "maxmind": {
33 | "queries_remaining": 11
34 | },
35 | "postal": {
36 | "code": "55401",
37 | "confidence": 33
38 | },
39 | "registered_country": {
40 | "geoname_id": 2,
41 | "iso_code": "CA",
42 | "names": {
43 | "en": "Canada"
44 | }
45 | },
46 | "represented_country": {
47 | "geoname_id": 3,
48 | "is_in_european_union": true,
49 | "iso_code": "GB",
50 | "names": {
51 | "en": "United Kingdom"
52 | },
53 | "type": "C"
54 | },
55 | "subdivisions": [
56 | {
57 | "confidence": 88,
58 | "geoname_id": 574635,
59 | "iso_code": "MN",
60 | "names": {
61 | "en": "Minnesota"
62 | }
63 | },
64 | {
65 | "iso_code": "TT"
66 | }
67 | ],
68 | "traits": {
69 | "autonomous_system_number": 1234,
70 | "autonomous_system_organization": "AS Organization",
71 | "connection_type": "Cable/DSL",
72 | "domain": "example.com",
73 | "ip_address": "1.2.3.4",
74 | "isp": "Comcast",
75 | "is_anonymous": true,
76 | "is_anonymous_vpn": true,
77 | "is_anycast": true,
78 | "is_hosting_provider": true,
79 | "is_public_proxy": true,
80 | "is_residential_proxy": true,
81 | "is_tor_exit_node": true,
82 | "organization": "Blorg",
83 | "static_ip_score": 1.3,
84 | "user_count": 2,
85 | "user_type": "college",
86 | "ip_risk_snapshot": 0.01
87 | },
88 | "anonymizer": {
89 | "confidence": 99,
90 | "is_anonymous": true,
91 | "is_anonymous_vpn": true,
92 | "is_hosting_provider": true,
93 | "is_public_proxy": true,
94 | "is_residential_proxy": true,
95 | "is_tor_exit_node": true,
96 | "network_last_seen": "2024-12-31",
97 | "provider_name": "NordVPN"
98 | }
99 | }
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/NetworkDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2;
2 |
3 | import com.fasterxml.jackson.core.JsonParser;
4 | import com.fasterxml.jackson.databind.DeserializationContext;
5 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
6 | import com.maxmind.db.Network;
7 | import java.io.IOException;
8 | import java.net.InetAddress;
9 | import java.net.UnknownHostException;
10 |
11 | /**
12 | * This class provides a deserializer for the Network class.
13 | */
14 | public final class NetworkDeserializer extends StdDeserializer {
15 |
16 | /**
17 | * Constructs a {@code NetworkDeserializer} with no type specified.
18 | */
19 | public NetworkDeserializer() {
20 | this(null);
21 | }
22 |
23 | /**
24 | * Constructs a @{code NetworkDeserializer} object.
25 | *
26 | * @param vc a class
27 | */
28 | public NetworkDeserializer(Class> vc) {
29 | super(vc);
30 | }
31 |
32 | @Override
33 | public Network deserialize(JsonParser jsonparser, DeserializationContext context)
34 | throws IOException {
35 |
36 | final var cidr = jsonparser.getValueAsString();
37 | if (cidr == null || cidr.isBlank()) {
38 | return null;
39 | }
40 | return parseCidr(cidr);
41 | }
42 |
43 | private static Network parseCidr(String cidr) throws IOException {
44 | final var parts = cidr.split("/", 2);
45 | if (parts.length != 2) {
46 | throw new IllegalArgumentException("Invalid CIDR format: " + cidr);
47 | }
48 |
49 | final var addrPart = parts[0];
50 | final var prefixPart = parts[1];
51 |
52 | final InetAddress address;
53 | try {
54 | address = InetAddress.getByName(addrPart);
55 | } catch (UnknownHostException e) {
56 | throw new IOException("Unknown host in CIDR: " + cidr, e);
57 | }
58 |
59 | final var prefixLength = parsePrefixLength(prefixPart, cidr);
60 |
61 | final var maxPrefix = (address.getAddress().length == 4) ? 32 : 128;
62 | if (prefixLength < 0 || prefixLength > maxPrefix) {
63 | throw new IllegalArgumentException(
64 | "Prefix length out of range (0-" + maxPrefix + ") for CIDR: " + cidr);
65 | }
66 |
67 | return new Network(address, prefixLength);
68 | }
69 |
70 | private static int parsePrefixLength(String prefixPart, String cidr) {
71 | try {
72 | return Integer.parseInt(prefixPart);
73 | } catch (NumberFormatException e) {
74 | throw new IllegalArgumentException(
75 | "Invalid prefix length in CIDR: " + cidr, e);
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/sample/Benchmark.java:
--------------------------------------------------------------------------------
1 | import java.io.File;
2 | import java.io.IOException;
3 | import java.net.InetAddress;
4 | import java.net.UnknownHostException;
5 | import java.util.Random;
6 |
7 | import com.maxmind.db.CHMCache;
8 | import com.maxmind.db.NoCache;
9 | import com.maxmind.db.NodeCache;
10 | import com.maxmind.db.Reader.FileMode;
11 | import com.maxmind.geoip2.DatabaseReader;
12 | import com.maxmind.geoip2.exception.AddressNotFoundException;
13 | import com.maxmind.geoip2.exception.GeoIp2Exception;
14 | import com.maxmind.geoip2.model.CityResponse;
15 |
16 | public class Benchmark {
17 |
18 | private final static int COUNT = 1000000;
19 | private final static int WARMUPS = 3;
20 | private final static int BENCHMARKS = 5;
21 | private final static boolean TRACE = false;
22 |
23 | public static void main(String[] args) throws GeoIp2Exception, IOException {
24 | File file = new File(args.length > 0 ? args[0] : "GeoLite2-City.mmdb");
25 | System.out.println("No caching");
26 | loop("Warming up", file, WARMUPS, NoCache.getInstance());
27 | loop("Benchmarking", file, BENCHMARKS, NoCache.getInstance());
28 |
29 | System.out.println("With caching");
30 | loop("Warming up", file, WARMUPS, new CHMCache());
31 | loop("Benchmarking", file, BENCHMARKS, new CHMCache());
32 | }
33 |
34 | private static void loop(String msg, File file, int loops, NodeCache cache)
35 | throws GeoIp2Exception, IOException {
36 | System.out.println(msg);
37 | for (int i = 0; i < loops; i++) {
38 | DatabaseReader r =
39 | new DatabaseReader.Builder(file).fileMode(FileMode.MEMORY_MAPPED).withCache(cache)
40 | .build();
41 | bench(r, COUNT, i);
42 | }
43 | System.out.println();
44 | }
45 |
46 | private static void bench(DatabaseReader r, int count, int seed)
47 | throws GeoIp2Exception, UnknownHostException {
48 | Random random = new Random(seed);
49 | long startTime = System.nanoTime();
50 | byte[] address = new byte[4];
51 | for (int i = 0; i < count; i++) {
52 | random.nextBytes(address);
53 | InetAddress ip = InetAddress.getByAddress(address);
54 | CityResponse t;
55 | try {
56 | t = r.city(ip);
57 | } catch (AddressNotFoundException | IOException e) {
58 | }
59 | if (TRACE) {
60 | if (i % 50000 == 0) {
61 | System.out.println(i + " " + ip);
62 | System.out.println(t);
63 | }
64 | }
65 | }
66 | long endTime = System.nanoTime();
67 |
68 | long duration = endTime - startTime;
69 | long qps = count * 1000000000L / duration;
70 | System.out.println("Requests per second: " + qps);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/model/DomainResponse.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
5 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
6 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
7 | import com.maxmind.db.MaxMindDbIpAddress;
8 | import com.maxmind.db.MaxMindDbNetwork;
9 | import com.maxmind.db.MaxMindDbParameter;
10 | import com.maxmind.db.Network;
11 | import com.maxmind.geoip2.JsonSerializable;
12 | import com.maxmind.geoip2.NetworkDeserializer;
13 | import java.net.InetAddress;
14 |
15 | /**
16 | * This class provides the GeoIP2 Domain model.
17 | *
18 | * @param domain The second level domain associated with the IP address. This will be something
19 | * like "example.com" or "example.co.uk", not "foo.example.com".
20 | * @param ipAddress The IP address that the data in the model is for.
21 | * @param network The network associated with the record. In particular, this is the largest
22 | * network where all the fields besides IP address have the same value.
23 | */
24 | public record DomainResponse(
25 | @JsonProperty("domain")
26 | @MaxMindDbParameter(name = "domain")
27 | String domain,
28 |
29 | @JsonProperty("ip_address")
30 | @MaxMindDbIpAddress
31 | InetAddress ipAddress,
32 |
33 | @JsonProperty("network")
34 | @JsonDeserialize(using = NetworkDeserializer.class)
35 | @MaxMindDbNetwork
36 | Network network
37 | ) implements JsonSerializable {
38 |
39 | /**
40 | * @return The second level domain associated with the IP address. This
41 | * will be something like "example.com" or "example.co.uk", not
42 | * "foo.example.com".
43 | * @deprecated Use {@link #domain()} instead. This method will be removed in 6.0.0.
44 | */
45 | @Deprecated(since = "5.0.0", forRemoval = true)
46 | public String getDomain() {
47 | return domain();
48 | }
49 |
50 | /**
51 | * @return The IP address that the data in the model is for.
52 | * @deprecated Use {@link #ipAddress()} instead. This method will be removed in 6.0.0.
53 | */
54 | @Deprecated(since = "5.0.0", forRemoval = true)
55 | @JsonProperty("ip_address")
56 | public String getIpAddress() {
57 | return ipAddress().getHostAddress();
58 | }
59 |
60 | /**
61 | * @return The network associated with the record. In particular, this is
62 | * the largest network where all the fields besides IP address have the
63 | * same value.
64 | * @deprecated Use {@link #network()} instead. This method will be removed in 6.0.0.
65 | */
66 | @Deprecated(since = "5.0.0", forRemoval = true)
67 | @JsonProperty
68 | @JsonSerialize(using = ToStringSerializer.class)
69 | public Network getNetwork() {
70 | return network();
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/test/java/com/maxmind/geoip2/NetworkDeserializerTest.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2;
2 |
3 | import com.fasterxml.jackson.core.JsonFactory;
4 | import com.fasterxml.jackson.core.JsonParser;
5 | import com.maxmind.db.Network;
6 | import org.junit.jupiter.api.Test;
7 |
8 | import java.io.IOException;
9 | import java.net.InetAddress;
10 |
11 | import static org.junit.jupiter.api.Assertions.*;
12 |
13 | final class NetworkDeserializerTest {
14 |
15 |
16 | private static Network parse(String jsonString) throws IOException {
17 | var deserializer = new NetworkDeserializer();
18 | JsonFactory jf = new JsonFactory();
19 | try (JsonParser p = jf.createParser(jsonString)) {
20 | p.nextToken();
21 | return deserializer.deserialize(p, null);
22 | }
23 | }
24 | private static void assertNetwork(Network n, String addr, int prefix) throws Exception {
25 | assertNotNull(n);
26 | assertEquals(InetAddress.getByName(addr), n.networkAddress());
27 | assertEquals(prefix, n.prefixLength());
28 | }
29 |
30 | @Test
31 | void parsesValidIPv4Cidr() throws Exception {
32 | Network actual = parse("\"1.2.3.0/24\"");
33 | assertNetwork(actual, "1.2.3.0", 24);
34 | }
35 |
36 | @Test
37 | void parsesValidIPv6Cidr() throws Exception {
38 | Network actual = parse("\"2001:db8::/32\"");
39 | assertNetwork(actual, "2001:db8::", 32);
40 | }
41 |
42 | @Test
43 | void rejectsWhitespaceInCidr() {
44 | assertThrows(IOException.class, () -> parse("\" 10.0.0.0/8 \""));
45 | }
46 |
47 |
48 |
49 |
50 | @Test
51 | void returnsNullOnJsonNull() throws Exception {
52 | Network actual = parse("null");
53 | assertNull(actual);
54 | }
55 |
56 | @Test
57 | void returnsNullOnBlankString() throws Exception {
58 | Network actual = parse("\" \"");
59 | assertNull(actual);
60 | }
61 |
62 | @Test
63 | void throwsOnMissingSlash() {
64 | assertThrows(IllegalArgumentException.class, () -> parse("\"1.2.3.0\""));
65 | }
66 |
67 | @Test
68 | void throwsOnNonNumericPrefix() {
69 | assertThrows(IllegalArgumentException.class, () -> parse("\"1.2.3.0/xx\""));
70 | }
71 |
72 | @Test
73 | void throwsOnOutOfRangePrefixIpv4() {
74 | assertThrows(IllegalArgumentException.class, () -> parse("\"1.2.3.0/64\""));
75 | assertThrows(IllegalArgumentException.class, () -> parse("\"1.2.3.0/-1\""));
76 | }
77 |
78 | @Test
79 | void throwsOnOutOfRangePrefixIpv6() {
80 | assertThrows(IllegalArgumentException.class, () -> parse("\"::/129\""));
81 | assertThrows(IllegalArgumentException.class, () -> parse("\"::/-1\""));
82 | }
83 |
84 | @Test
85 | void wrapsUnknownHostInIOException() {
86 | IOException ex = assertThrows(IOException.class, () -> parse("\"999.999.999.999/24\""));
87 | assertNotNull(ex.getCause());
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/test/resources/test-data/insights1.json:
--------------------------------------------------------------------------------
1 | {
2 | "city": {
3 | "geoname_id": "2655045",
4 | "names": {
5 | "en": "Boxford"
6 | }
7 | },
8 | "continent": {
9 | "code": "EU",
10 | "geoname_id": 6255148,
11 | "names": {
12 | "de": "Europa",
13 | "en": "Europe",
14 | "es": "Europa",
15 | "fr": "Europe",
16 | "ja": "ヨーロッパ",
17 | "pt-BR": "Europa",
18 | "ru": "Европа",
19 | "zh-CN": "欧洲"
20 | }
21 | },
22 | "country": {
23 | "geoname_id": 2635167,
24 | "is_in_european_union": true,
25 | "iso_code": "GB",
26 | "names": {
27 | "de": "Vereinigtes Königreich",
28 | "en": "United Kingdom",
29 | "es": "Reino Unido",
30 | "fr": "Royaume-Uni",
31 | "ja": "イギリス",
32 | "pt-BR": "Reino Unido",
33 | "ru": "Великобритания",
34 | "zh-CN": "英国"
35 | }
36 | },
37 | "location": {
38 | "accuracy_radius": 100,
39 | "latitude": "51.7500",
40 | "longitude": "-1.2500",
41 | "time_zone": "Europe/London"
42 | },
43 | "maxmind": {
44 | "queries_remaining": 11
45 | },
46 | "postal": {
47 | "code": "OX1"
48 | },
49 | "registered_country": {
50 | "geoname_id": 3017382,
51 | "is_in_european_union": true,
52 | "iso_code": "FR",
53 | "names": {
54 | "de": "Frankreich",
55 | "en": "France",
56 | "es": "Francia",
57 | "fr": "France",
58 | "ja": "フランス共和国",
59 | "pt-BR": "França",
60 | "ru": "Франция",
61 | "zh-CN": "法国"
62 | }
63 | },
64 | "subdivisions": [
65 | {
66 | "geoname_id": 6269131,
67 | "iso_code": "ENG",
68 | "names": {
69 | "en": "England",
70 | "es": "Inglaterra",
71 | "fr": "Angleterre",
72 | "pt-BR": "Inglaterra"
73 | }
74 | },
75 | {
76 | "geoname_id": 3333217,
77 | "iso_code": "WBK",
78 | "names": {
79 | "en": "West Berkshire",
80 | "ru": "Западный Беркшир",
81 | "zh-CN": "西伯克郡"
82 | }
83 | }
84 | ],
85 | "traits": {
86 | "autonomous_system_number": 1234,
87 | "autonomous_system_organization": "AS Organization",
88 | "connection_type": "Cable/DSL",
89 | "domain": "example.com",
90 | "ip_address": "1.2.3.4",
91 | "isp": "Comcast",
92 | "is_anonymous": true,
93 | "is_anonymous_vpn": true,
94 | "is_anycast": true,
95 | "is_hosting_provider": true,
96 | "is_public_proxy": true,
97 | "is_tor_exit_node": true,
98 | "organization": "Blorg",
99 | "static_ip_score": 1.3,
100 | "user_count": 2,
101 | "user_type": "college",
102 | "ip_risk_snapshot": 0.01
103 | },
104 | "anonymizer": {
105 | "confidence": 99,
106 | "is_anonymous": true,
107 | "is_anonymous_vpn": true,
108 | "is_hosting_provider": true,
109 | "is_public_proxy": true,
110 | "is_residential_proxy": true,
111 | "is_tor_exit_node": true,
112 | "network_last_seen": "2024-12-31",
113 | "provider_name": "NordVPN"
114 | }
115 | }
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/record/Anonymizer.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.record;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.maxmind.geoip2.JsonSerializable;
5 | import java.time.LocalDate;
6 |
7 | /**
8 | *
9 | * Contains data for the anonymizer record associated with an IP address.
10 | *
11 | *
12 | * This record is returned by the GeoIP2 Precision Insights web service.
13 | *
14 | *
15 | * @param confidence A score ranging from 1 to 99 that is our percent confidence that the
16 | * network is currently part of an actively used VPN service. This is only
17 | * available from the GeoIP2 Precision Insights web service.
18 | * @param isAnonymous Whether the IP address belongs to any sort of anonymous network.
19 | * @param isAnonymousVpn Whether the IP address is registered to an anonymous VPN provider. If a
20 | * VPN provider does not register subnets under names associated with them,
21 | * we will likely only flag their IP ranges using isHostingProvider.
22 | * @param isHostingProvider Whether the IP address belongs to a hosting or VPN provider (see
23 | * description of isAnonymousVpn).
24 | * @param isPublicProxy Whether the IP address belongs to a public proxy.
25 | * @param isResidentialProxy Whether the IP address is on a suspected anonymizing network and
26 | * belongs to a residential ISP.
27 | * @param isTorExitNode Whether the IP address is a Tor exit node.
28 | * @param networkLastSeen The last day that the network was sighted in our analysis of anonymized
29 | * networks. This is only available from the GeoIP2 Precision Insights web
30 | * service.
31 | * @param providerName The name of the VPN provider (e.g., NordVPN, SurfShark, etc.) associated
32 | * with the network. This is only available from the GeoIP2 Precision Insights
33 | * web service.
34 | */
35 | public record Anonymizer(
36 | @JsonProperty("confidence")
37 | Integer confidence,
38 |
39 | @JsonProperty("is_anonymous")
40 | boolean isAnonymous,
41 |
42 | @JsonProperty("is_anonymous_vpn")
43 | boolean isAnonymousVpn,
44 |
45 | @JsonProperty("is_hosting_provider")
46 | boolean isHostingProvider,
47 |
48 | @JsonProperty("is_public_proxy")
49 | boolean isPublicProxy,
50 |
51 | @JsonProperty("is_residential_proxy")
52 | boolean isResidentialProxy,
53 |
54 | @JsonProperty("is_tor_exit_node")
55 | boolean isTorExitNode,
56 |
57 | @JsonProperty("network_last_seen")
58 | LocalDate networkLastSeen,
59 |
60 | @JsonProperty("provider_name")
61 | String providerName
62 | ) implements JsonSerializable {
63 |
64 | /**
65 | * Constructs an {@code Anonymizer} record with {@code null} values for all the nullable
66 | * fields and {@code false} for all boolean fields.
67 | */
68 | public Anonymizer() {
69 | this(null, false, false, false, false, false, false, null, null);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/model/AsnResponse.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
5 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
6 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
7 | import com.maxmind.db.MaxMindDbIpAddress;
8 | import com.maxmind.db.MaxMindDbNetwork;
9 | import com.maxmind.db.MaxMindDbParameter;
10 | import com.maxmind.db.Network;
11 | import com.maxmind.geoip2.JsonSerializable;
12 | import com.maxmind.geoip2.NetworkDeserializer;
13 | import java.net.InetAddress;
14 |
15 | /**
16 | * This class provides the GeoLite2 ASN model.
17 | *
18 | * @param autonomousSystemNumber The autonomous system number associated with the IP address.
19 | * @param autonomousSystemOrganization The organization associated with the registered autonomous
20 | * system number for the IP address.
21 | * @param ipAddress The IP address that the data in the model is for.
22 | * @param network The network associated with the record. In particular, this is the largest
23 | * network where all the fields besides IP address have the same value.
24 | */
25 | public record AsnResponse(
26 | @JsonProperty("autonomous_system_number")
27 | @MaxMindDbParameter(name = "autonomous_system_number")
28 | Long autonomousSystemNumber,
29 |
30 | @JsonProperty("autonomous_system_organization")
31 | @MaxMindDbParameter(name = "autonomous_system_organization")
32 | String autonomousSystemOrganization,
33 |
34 | @JsonProperty("ip_address")
35 | @MaxMindDbIpAddress
36 | InetAddress ipAddress,
37 |
38 | @JsonProperty("network")
39 | @JsonDeserialize(using = NetworkDeserializer.class)
40 | @MaxMindDbNetwork
41 | Network network
42 | ) implements JsonSerializable {
43 |
44 | /**
45 | * @return The autonomous system number associated with the IP address.
46 | * @deprecated Use {@link #autonomousSystemNumber()} instead. This method will be removed
47 | * in 6.0.0.
48 | */
49 | @Deprecated(since = "5.0.0", forRemoval = true)
50 | @JsonProperty("autonomous_system_number")
51 | public Long getAutonomousSystemNumber() {
52 | return autonomousSystemNumber();
53 | }
54 |
55 | /**
56 | * @return The organization associated with the registered autonomous system
57 | * number for the IP address
58 | * @deprecated Use {@link #autonomousSystemOrganization()} instead. This method will be
59 | * removed in 6.0.0.
60 | */
61 | @Deprecated(since = "5.0.0", forRemoval = true)
62 | @JsonProperty("autonomous_system_organization")
63 | public String getAutonomousSystemOrganization() {
64 | return autonomousSystemOrganization();
65 | }
66 |
67 | /**
68 | * @return The IP address that the data in the model is for.
69 | * @deprecated Use {@link #ipAddress()} instead. This method will be removed in 6.0.0.
70 | */
71 | @Deprecated(since = "5.0.0", forRemoval = true)
72 | @JsonProperty("ip_address")
73 | public String getIpAddress() {
74 | return ipAddress().getHostAddress();
75 | }
76 |
77 | /**
78 | * @return The network associated with the record. In particular, this is
79 | * the largest network where all the fields besides IP address have the
80 | * same value.
81 | * @deprecated Use {@link #network()} instead. This method will be removed in 6.0.0.
82 | */
83 | @Deprecated(since = "5.0.0", forRemoval = true)
84 | @JsonProperty
85 | @JsonSerialize(using = ToStringSerializer.class)
86 | public Network getNetwork() {
87 | return network();
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/model/AnonymousIpResponse.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
5 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
6 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
7 | import com.maxmind.db.MaxMindDbIpAddress;
8 | import com.maxmind.db.MaxMindDbNetwork;
9 | import com.maxmind.db.MaxMindDbParameter;
10 | import com.maxmind.db.Network;
11 | import com.maxmind.geoip2.JsonSerializable;
12 | import com.maxmind.geoip2.NetworkDeserializer;
13 | import java.net.InetAddress;
14 |
15 | /**
16 | * This class provides the GeoIP2 Anonymous IP model.
17 | *
18 | * @param ipAddress The IP address that the data in the model is for.
19 | * @param isAnonymous Whether the IP address belongs to any sort of anonymous network.
20 | * @param isAnonymousVpn Whether the IP address is registered to an anonymous VPN provider. If a
21 | * VPN provider does not register subnets under names associated with them,
22 | * we will likely only flag their IP ranges using isHostingProvider.
23 | * @param isHostingProvider Whether the IP address belongs to a hosting or VPN provider (see
24 | * description of isAnonymousVpn).
25 | * @param isPublicProxy Whether the IP address belongs to a public proxy.
26 | * @param isResidentialProxy Whether the IP address is on a suspected anonymizing network and
27 | * belongs to a residential ISP.
28 | * @param isTorExitNode Whether the IP address is a Tor exit node.
29 | * @param network The network associated with the record. In particular, this is the largest
30 | * network where all the fields besides IP address have the same value.
31 | */
32 | public record AnonymousIpResponse(
33 | @JsonProperty("ip_address")
34 | @MaxMindDbIpAddress
35 | InetAddress ipAddress,
36 |
37 | @JsonProperty("is_anonymous")
38 | @MaxMindDbParameter(name = "is_anonymous", useDefault = true)
39 | boolean isAnonymous,
40 |
41 | @JsonProperty("is_anonymous_vpn")
42 | @MaxMindDbParameter(name = "is_anonymous_vpn", useDefault = true)
43 | boolean isAnonymousVpn,
44 |
45 | @JsonProperty("is_hosting_provider")
46 | @MaxMindDbParameter(name = "is_hosting_provider", useDefault = true)
47 | boolean isHostingProvider,
48 |
49 | @JsonProperty("is_public_proxy")
50 | @MaxMindDbParameter(name = "is_public_proxy", useDefault = true)
51 | boolean isPublicProxy,
52 |
53 | @JsonProperty("is_residential_proxy")
54 | @MaxMindDbParameter(name = "is_residential_proxy", useDefault = true)
55 | boolean isResidentialProxy,
56 |
57 | @JsonProperty("is_tor_exit_node")
58 | @MaxMindDbParameter(name = "is_tor_exit_node", useDefault = true)
59 | boolean isTorExitNode,
60 |
61 | @JsonProperty("network")
62 | @JsonDeserialize(using = NetworkDeserializer.class)
63 | @MaxMindDbNetwork
64 | Network network
65 | ) implements JsonSerializable {
66 |
67 | /**
68 | * @return The IP address that the data in the model is for.
69 | * @deprecated Use {@link #ipAddress()} instead. This method will be removed in 6.0.0.
70 | */
71 | @Deprecated(since = "5.0.0", forRemoval = true)
72 | @JsonProperty("ip_address")
73 | public String getIpAddress() {
74 | return ipAddress().getHostAddress();
75 | }
76 |
77 | /**
78 | * @return The network associated with the record. In particular, this is
79 | * the largest network where all the fields besides IP address have the
80 | * same value.
81 | * @deprecated Use {@link #network()} instead. This method will be removed in 6.0.0.
82 | */
83 | @Deprecated(since = "5.0.0", forRemoval = true)
84 | @JsonProperty
85 | @JsonSerialize(using = ToStringSerializer.class)
86 | public Network getNetwork() {
87 | return network();
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/record/Continent.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.record;
2 |
3 | import com.fasterxml.jackson.annotation.JacksonInject;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.maxmind.db.MaxMindDbParameter;
6 | import com.maxmind.geoip2.NamedRecord;
7 | import java.util.List;
8 | import java.util.Map;
9 |
10 | /**
11 | *
12 | * Contains data for the continent record associated with an IP address.
13 | *
14 | *
15 | * Do not use any of the continent names as a database or map key. Use the
16 | * value returned by {@link #geonameId()} or {@link #code()} instead.
17 | *
18 | *
19 | * @param locales The locales to use for retrieving localized names.
20 | * @param code A two character continent code like "NA" (North America) or "OC"
21 | * (Oceania).
22 | * @param geonameId The GeoName ID for the continent.
23 | * @param names A {@link Map} from locale codes to the name in that locale.
24 | */
25 | public record Continent(
26 | @JacksonInject("locales")
27 | @MaxMindDbParameter(name = "locales")
28 | List locales,
29 |
30 | @JsonProperty("code")
31 | @MaxMindDbParameter(name = "code")
32 | String code,
33 |
34 | @JsonProperty("geoname_id")
35 | @MaxMindDbParameter(name = "geoname_id")
36 | Long geonameId,
37 |
38 | @JsonProperty("names")
39 | @MaxMindDbParameter(name = "names")
40 | Map names
41 | ) implements NamedRecord {
42 |
43 | /**
44 | * Compact canonical constructor that ensures immutability and handles null values.
45 | */
46 | public Continent {
47 | locales = locales != null ? List.copyOf(locales) : List.of();
48 | names = names != null ? Map.copyOf(names) : Map.of();
49 | }
50 |
51 | /**
52 | * Constructs an instance of {@code Continent} with no data.
53 | */
54 | public Continent() {
55 | this(null, null, null, null);
56 | }
57 |
58 | /**
59 | * Constructs an instance of {@code Continent}.
60 | *
61 | * @param continent The {@code Continent} object to copy.
62 | * @param locales The locales to use.
63 | */
64 | public Continent(
65 | Continent continent,
66 | List locales
67 | ) {
68 | this(
69 | locales,
70 | continent.code(),
71 | continent.geonameId(),
72 | continent.names()
73 | );
74 | }
75 |
76 | /**
77 | * @return A two character continent code like "NA" (North America) or "OC"
78 | * (Oceania).
79 | * @deprecated Use {@link #code()} instead. This method will be removed in 6.0.0.
80 | */
81 | @Deprecated(since = "5.0.0", forRemoval = true)
82 | public String getCode() {
83 | return code();
84 | }
85 |
86 | /**
87 | * @return The GeoName ID for the continent.
88 | * @deprecated Use {@link #geonameId()} instead. This method will be removed in 6.0.0.
89 | */
90 | @Deprecated(since = "5.0.0", forRemoval = true)
91 | @JsonProperty("geoname_id")
92 | public Long getGeoNameId() {
93 | return geonameId();
94 | }
95 |
96 | /**
97 | * @return The name of the continent based on the locales list.
98 | * @deprecated Use {@link #name()} instead. This method will be removed in 6.0.0.
99 | */
100 | @Deprecated(since = "5.0.0", forRemoval = true)
101 | @com.fasterxml.jackson.annotation.JsonIgnore
102 | public String getName() {
103 | return name();
104 | }
105 |
106 | /**
107 | * @return A {@link Map} from locale codes to the name in that locale.
108 | * @deprecated Use {@link #names()} instead. This method will be removed in 6.0.0.
109 | */
110 | @Deprecated(since = "5.0.0", forRemoval = true)
111 | @JsonProperty("names")
112 | public Map getNames() {
113 | return names();
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/record/City.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.record;
2 |
3 | import com.fasterxml.jackson.annotation.JacksonInject;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.maxmind.db.MaxMindDbParameter;
6 | import com.maxmind.geoip2.NamedRecord;
7 | import java.util.List;
8 | import java.util.Map;
9 |
10 | /**
11 | *
12 | * City-level data associated with an IP address.
13 | *
14 | *
15 | * Do not use any of the city names as a database or map key. Use the value
16 | * returned by {@link #geonameId()} instead.
17 | *
18 | *
19 | * @param locales The locales to use for retrieving localized names.
20 | * @param confidence A value from 0-100 indicating MaxMind's confidence that the city
21 | * is correct. This attribute is only available from the Insights
22 | * web service and the GeoIP2 Enterprise database.
23 | * @param geonameId The GeoName ID for the city.
24 | * @param names A {@link Map} from locale codes to the name in that locale.
25 | */
26 | public record City(
27 | @JacksonInject("locales")
28 | @MaxMindDbParameter(name = "locales")
29 | List locales,
30 |
31 | @JsonProperty("confidence")
32 | @MaxMindDbParameter(name = "confidence")
33 | Integer confidence,
34 |
35 | @JsonProperty("geoname_id")
36 | @MaxMindDbParameter(name = "geoname_id")
37 | Long geonameId,
38 |
39 | @JsonProperty("names")
40 | @MaxMindDbParameter(name = "names")
41 | Map names
42 | ) implements NamedRecord {
43 |
44 | /**
45 | * Compact canonical constructor that ensures immutability and handles null values.
46 | */
47 | public City {
48 | locales = locales != null ? List.copyOf(locales) : List.of();
49 | names = names != null ? Map.copyOf(names) : Map.of();
50 | }
51 |
52 | /**
53 | * Constructs an instance of {@code City} with no data.
54 | */
55 | public City() {
56 | this(null, null, null, null);
57 | }
58 |
59 | /**
60 | * Constructs an instance of {@code City}.
61 | *
62 | * @param city The {@code City} object to copy.
63 | * @param locales The locales to use.
64 | */
65 | public City(
66 | City city,
67 | List locales
68 | ) {
69 | this(
70 | locales,
71 | city.confidence(),
72 | city.geonameId(),
73 | city.names()
74 | );
75 | }
76 |
77 | /**
78 | * @return A value from 0-100 indicating MaxMind's confidence that the city
79 | * is correct. This attribute is only available from the Insights
80 | * web service and the GeoIP2 Enterprise database.
81 | * @deprecated Use {@link #confidence()} instead. This method will be removed in 6.0.0.
82 | */
83 | @Deprecated(since = "5.0.0", forRemoval = true)
84 | public Integer getConfidence() {
85 | return confidence();
86 | }
87 |
88 | /**
89 | * @return The GeoName ID for the city.
90 | * @deprecated Use {@link #geonameId()} instead. This method will be removed in 6.0.0.
91 | */
92 | @Deprecated(since = "5.0.0", forRemoval = true)
93 | @JsonProperty("geoname_id")
94 | public Long getGeoNameId() {
95 | return geonameId();
96 | }
97 |
98 | /**
99 | * @return The name of the city based on the locales list passed to the
100 | * constructor.
101 | * @deprecated Use {@link #name()} instead. This method will be removed in 6.0.0.
102 | */
103 | @Deprecated(since = "5.0.0", forRemoval = true)
104 | @com.fasterxml.jackson.annotation.JsonIgnore
105 | public String getName() {
106 | return name();
107 | }
108 |
109 | /**
110 | * @return A {@link Map} from locale codes to the name in that locale.
111 | * @deprecated Use {@link #names()} instead. This method will be removed in 6.0.0.
112 | */
113 | @Deprecated(since = "5.0.0", forRemoval = true)
114 | @JsonProperty("names")
115 | public Map getNames() {
116 | return names();
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/model/ConnectionTypeResponse.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.fasterxml.jackson.annotation.JsonValue;
6 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
7 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
8 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
9 | import com.maxmind.db.MaxMindDbCreator;
10 | import com.maxmind.db.MaxMindDbIpAddress;
11 | import com.maxmind.db.MaxMindDbNetwork;
12 | import com.maxmind.db.MaxMindDbParameter;
13 | import com.maxmind.db.Network;
14 | import com.maxmind.geoip2.JsonSerializable;
15 | import com.maxmind.geoip2.NetworkDeserializer;
16 | import java.net.InetAddress;
17 |
18 | /**
19 | * This class provides the GeoIP2 Connection-Type model.
20 | *
21 | * @param connectionType The connection type of the IP address.
22 | * @param ipAddress The IP address that the data in the model is for.
23 | * @param network The network associated with the record. In particular, this is the largest
24 | * network where all the fields besides IP address have the same value.
25 | */
26 | public record ConnectionTypeResponse(
27 | @JsonProperty("connection_type")
28 | @MaxMindDbParameter(name = "connection_type")
29 | ConnectionType connectionType,
30 |
31 | @JsonProperty("ip_address")
32 | @MaxMindDbIpAddress
33 | InetAddress ipAddress,
34 |
35 | @JsonProperty("network")
36 | @JsonDeserialize(using = NetworkDeserializer.class)
37 | @MaxMindDbNetwork
38 | Network network
39 | ) implements JsonSerializable {
40 |
41 | /**
42 | * The enumerated values that connection-type may take.
43 | */
44 | public enum ConnectionType {
45 | DIALUP("Dialup"),
46 | CABLE_DSL("Cable/DSL"),
47 | CORPORATE("Corporate"),
48 | CELLULAR("Cellular"),
49 | SATELLITE("Satellite");
50 |
51 | private final String name;
52 |
53 | ConnectionType(String name) {
54 | this.name = name;
55 | }
56 |
57 | /*
58 | * (non-Javadoc)
59 | *
60 | * @see java.lang.Enum#toString()
61 | */
62 | @JsonValue
63 | @Override
64 | public String toString() {
65 | return this.name;
66 | }
67 |
68 | /**
69 | * Creates an instance of {@code ConnectionTypeResponse} from a string.
70 | *
71 | * @param s The string to create the instance from.
72 | */
73 | @JsonCreator
74 | @MaxMindDbCreator
75 | public static ConnectionType fromString(String s) {
76 | if (s == null) {
77 | return null;
78 | }
79 |
80 | return switch (s) {
81 | case "Dialup" -> ConnectionType.DIALUP;
82 | case "Cable/DSL" -> ConnectionType.CABLE_DSL;
83 | case "Corporate" -> ConnectionType.CORPORATE;
84 | case "Cellular" -> ConnectionType.CELLULAR;
85 | case "Satellite" -> ConnectionType.SATELLITE;
86 | default -> null;
87 | };
88 | }
89 | }
90 |
91 | /**
92 | * @return The connection type of the IP address.
93 | * @deprecated Use {@link #connectionType()} instead. This method will be removed in 6.0.0.
94 | */
95 | @Deprecated(since = "5.0.0", forRemoval = true)
96 | @JsonProperty("connection_type")
97 | public ConnectionType getConnectionType() {
98 | return connectionType();
99 | }
100 |
101 | /**
102 | * @return The IP address that the data in the model is for.
103 | * @deprecated Use {@link #ipAddress()} instead. This method will be removed in 6.0.0.
104 | */
105 | @Deprecated(since = "5.0.0", forRemoval = true)
106 | @JsonProperty("ip_address")
107 | public String getIpAddress() {
108 | return ipAddress().getHostAddress();
109 | }
110 |
111 | /**
112 | * @return The network associated with the record. In particular, this is
113 | * the largest network where all the fields besides IP address have the
114 | * same value.
115 | * @deprecated Use {@link #network()} instead. This method will be removed in 6.0.0.
116 | */
117 | @Deprecated(since = "5.0.0", forRemoval = true)
118 | @JsonProperty
119 | @JsonSerialize(using = ToStringSerializer.class)
120 | public Network getNetwork() {
121 | return network();
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/dev-bin/release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -eu -o pipefail
4 |
5 | # Pre-flight checks - verify all required tools are available and configured
6 | # before making any changes to the repository
7 |
8 | check_command() {
9 | if ! command -v "$1" &>/dev/null; then
10 | echo "Error: $1 is not installed or not in PATH"
11 | exit 1
12 | fi
13 | }
14 |
15 | # Verify gh CLI is authenticated
16 | if ! gh auth status &>/dev/null; then
17 | echo "Error: gh CLI is not authenticated. Run 'gh auth login' first."
18 | exit 1
19 | fi
20 |
21 | # Verify we can access this repository via gh
22 | if ! gh repo view --json name &>/dev/null; then
23 | echo "Error: Cannot access repository via gh. Check your authentication and repository access."
24 | exit 1
25 | fi
26 |
27 | # Verify git can connect to the remote (catches SSH key issues, etc.)
28 | if ! git ls-remote origin &>/dev/null; then
29 | echo "Error: Cannot connect to git remote. Check your git credentials/SSH keys."
30 | exit 1
31 | fi
32 |
33 | check_command perl
34 | check_command mvn
35 |
36 | # Check that we're not on the main branch
37 | current_branch=$(git branch --show-current)
38 | if [ "$current_branch" = "main" ]; then
39 | echo "Error: Releases should not be done directly on the main branch."
40 | echo "Please create a release branch and run this script from there."
41 | exit 1
42 | fi
43 |
44 | # Fetch latest changes and check that we're not behind origin/main
45 | echo "Fetching from origin..."
46 | git fetch origin
47 |
48 | if ! git merge-base --is-ancestor origin/main HEAD; then
49 | echo "Error: Current branch is behind origin/main."
50 | echo "Please merge or rebase with origin/main before releasing."
51 | exit 1
52 | fi
53 |
54 | changelog=$(cat CHANGELOG.md)
55 |
56 | regex='
57 | ([0-9]+\.[0-9]+\.[0-9]+[a-zA-Z0-9\-]*) \(([0-9]{4}-[0-9]{2}-[0-9]{2})\)
58 | -*
59 |
60 | ((.|
61 | )*)
62 | '
63 |
64 | if [[ ! $changelog =~ $regex ]]; then
65 | echo "Could not find date line in change log!"
66 | exit 1
67 | fi
68 |
69 | version="${BASH_REMATCH[1]}"
70 | date="${BASH_REMATCH[2]}"
71 | notes="$(echo "${BASH_REMATCH[3]}" | sed -n -e '/^[0-9]\+\.[0-9]\+\.[0-9]\+/,$!p')"
72 |
73 | if [[ "$date" != "$(date +"%Y-%m-%d")" ]]; then
74 | echo "$date is not today!"
75 | exit 1
76 | fi
77 |
78 | tag="v$version"
79 |
80 | if [ -n "$(git status --porcelain)" ]; then
81 | echo ". is not clean." >&2
82 | exit 1
83 | fi
84 |
85 | if [ ! -d .gh-pages ]; then
86 | echo "Checking out gh-pages in .gh-pages"
87 | git clone -b gh-pages git@github.com:maxmind/GeoIP2-java.git .gh-pages
88 | pushd .gh-pages
89 | else
90 | echo "Updating .gh-pages"
91 | pushd .gh-pages
92 | git pull
93 | fi
94 |
95 | if [ -n "$(git status --porcelain)" ]; then
96 | echo ".gh-pages is not clean" >&2
97 | exit 1
98 | fi
99 |
100 | popd
101 |
102 | mvn versions:display-plugin-updates
103 | mvn versions:display-dependency-updates
104 |
105 | read -r -n 1 -p "Continue given above dependencies? (y/n) " should_continue
106 |
107 | if [ "$should_continue" != "y" ]; then
108 | echo "Aborting"
109 | exit 1
110 | fi
111 |
112 | mvn test
113 |
114 | read -r -n 1 -p "Continue given above tests? (y/n) " should_continue
115 |
116 | if [ "$should_continue" != "y" ]; then
117 | echo "Aborting"
118 | exit 1
119 | fi
120 |
121 | page=.gh-pages/index.md
122 | cat <$page
123 | ---
124 | layout: default
125 | title: MaxMind GeoIP2 Java API
126 | language: java
127 | version: $tag
128 | ---
129 |
130 | EOF
131 |
132 | mvn versions:set -DnewVersion="$version"
133 |
134 | perl -pi -e "s/(?<=)[^<]*/$version/" README.md
135 | perl -pi -e "s/(?<=com\.maxmind\.geoip2\:geoip2\:)\d+\.\d+\.\d+([\w\-]+)?/$version/" README.md
136 |
137 | cat README.md >>$page
138 |
139 | git diff
140 |
141 | read -r -n 1 -p "Commit changes? " should_commit
142 | if [ "$should_commit" != "y" ]; then
143 | echo "Aborting"
144 | exit 1
145 | fi
146 | git add README.md pom.xml
147 | git commit -m "Preparing for $version"
148 |
149 | mvn clean deploy
150 |
151 | rm -fr ".gh-pages/doc/$tag"
152 | cp -r target/reports/apidocs ".gh-pages/doc/$tag"
153 | rm .gh-pages/doc/latest
154 | ln -fs "$tag" .gh-pages/doc/latest
155 |
156 | pushd .gh-pages
157 |
158 | git add doc/
159 | git commit -m "Updated for $tag" -a
160 |
161 | echo "Release notes for $version:
162 |
163 | $notes
164 |
165 | "
166 | read -r -n 1 -p "Push to origin? " should_push
167 |
168 | if [ "$should_push" != "y" ]; then
169 | echo "Aborting"
170 | exit 1
171 | fi
172 |
173 | git push
174 |
175 | popd
176 |
177 | git push
178 |
179 | gh release create --target "$(git branch --show-current)" -t "$version" -n "$notes" "$tag" \
180 | "target/geoip2-$version-with-dependencies.zip" \
181 | "target/geoip2-$version-with-dependencies.zip.asc"
182 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/model/IpRiskResponse.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
5 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
6 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
7 | import com.maxmind.db.MaxMindDbIpAddress;
8 | import com.maxmind.db.MaxMindDbNetwork;
9 | import com.maxmind.db.MaxMindDbParameter;
10 | import com.maxmind.db.Network;
11 | import com.maxmind.geoip2.JsonSerializable;
12 | import com.maxmind.geoip2.NetworkDeserializer;
13 | import java.net.InetAddress;
14 |
15 | /**
16 | * This class provides the GeoIP2 IP Risk model.
17 | *
18 | * @param ipAddress The IP address that the data in the model is for.
19 | * @param isAnonymous Whether the IP address belongs to any sort of anonymous network.
20 | * @param isAnonymousVpn Whether the IP address is registered to an anonymous VPN provider. If a
21 | * VPN provider does not register subnets under names associated with them,
22 | * we will likely only flag their IP ranges using isHostingProvider.
23 | * @param isHostingProvider Whether the IP address belongs to a hosting or VPN provider (see
24 | * description of isAnonymousVpn).
25 | * @param isPublicProxy Whether the IP address belongs to a public proxy.
26 | * @param isResidentialProxy Whether the IP address is on a suspected anonymizing network and
27 | * belongs to a residential ISP.
28 | * @param isTorExitNode Whether the IP address is a Tor exit node.
29 | * @param network The network associated with the record. In particular, this is the largest
30 | * network where all the fields besides IP address have the same value.
31 | * @param ipRisk The IP risk score for the IP address. A value of 0.0 indicates that the
32 | * risk score was not set in the database. This is a limitation of primitive
33 | * types in Java - the value cannot be null. In a future major version, this
34 | * field may be changed to a nullable {@code Double} to distinguish between
35 | * "no data" and "zero risk".
36 | */
37 | // TODO: In the next major version (6.0.0), consider changing ipRisk to Double
38 | // to allow null values, distinguishing "no data" from "zero risk".
39 | public record IpRiskResponse(
40 | @JsonProperty("ip_address")
41 | @MaxMindDbIpAddress
42 | InetAddress ipAddress,
43 |
44 | @JsonProperty("is_anonymous")
45 | @MaxMindDbParameter(name = "is_anonymous", useDefault = true)
46 | boolean isAnonymous,
47 |
48 | @JsonProperty("is_anonymous_vpn")
49 | @MaxMindDbParameter(name = "is_anonymous_vpn", useDefault = true)
50 | boolean isAnonymousVpn,
51 |
52 | @JsonProperty("is_hosting_provider")
53 | @MaxMindDbParameter(name = "is_hosting_provider", useDefault = true)
54 | boolean isHostingProvider,
55 |
56 | @JsonProperty("is_public_proxy")
57 | @MaxMindDbParameter(name = "is_public_proxy", useDefault = true)
58 | boolean isPublicProxy,
59 |
60 | @JsonProperty("is_residential_proxy")
61 | @MaxMindDbParameter(name = "is_residential_proxy", useDefault = true)
62 | boolean isResidentialProxy,
63 |
64 | @JsonProperty("is_tor_exit_node")
65 | @MaxMindDbParameter(name = "is_tor_exit_node", useDefault = true)
66 | boolean isTorExitNode,
67 |
68 | @JsonProperty("network")
69 | @MaxMindDbNetwork
70 | @JsonDeserialize(using = NetworkDeserializer.class)
71 | Network network,
72 |
73 | @JsonProperty("ip_risk")
74 | @MaxMindDbParameter(name = "ip_risk", useDefault = true)
75 | double ipRisk
76 | ) implements JsonSerializable {
77 |
78 | /**
79 | * @return The IP address that the data in the model is for.
80 | * @deprecated Use {@link #ipAddress()} instead. This method will be removed in 6.0.0.
81 | */
82 | @Deprecated(since = "5.0.0", forRemoval = true)
83 | @JsonProperty("ip_address")
84 | public String getIpAddress() {
85 | return ipAddress().getHostAddress();
86 | }
87 |
88 | /**
89 | * @return The network associated with the record. In particular, this is
90 | * the largest network where all the fields besides IP address have the
91 | * same value.
92 | * @deprecated Use {@link #network()} instead. This method will be removed in 6.0.0.
93 | */
94 | @Deprecated(since = "5.0.0", forRemoval = true)
95 | @JsonProperty
96 | @JsonSerialize(using = ToStringSerializer.class)
97 | public Network getNetwork() {
98 | return network();
99 | }
100 |
101 | /**
102 | * @return The IP risk of a model.
103 | * @deprecated Use {@link #ipRisk()} instead. This method will be removed in 6.0.0.
104 | */
105 | @Deprecated(since = "5.0.0", forRemoval = true)
106 | @JsonProperty("ip_risk")
107 | public double getIpRisk() {
108 | return ipRisk();
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/record/Subdivision.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.record;
2 |
3 | import com.fasterxml.jackson.annotation.JacksonInject;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.maxmind.db.MaxMindDbParameter;
6 | import com.maxmind.geoip2.NamedRecord;
7 | import java.util.List;
8 | import java.util.Map;
9 |
10 | /**
11 | *
12 | * Contains data for the subdivisions associated with an IP address.
13 | *
14 | *
15 | * Do not use any of the subdivision names as a database or map key. Use the
16 | * value returned by {@link #geonameId()} or {@link #isoCode()} instead.
17 | *
18 | *
19 | * @param locales The locales to use for retrieving localized names.
20 | * @param confidence A value from 0-100 indicating MaxMind's confidence that the
21 | * subdivision is correct. This attribute is only available from
22 | * the Insights web service and the GeoIP2 Enterprise database.
23 | * @param geonameId The GeoName ID for the subdivision.
24 | * @param isoCode A string up to three characters long containing the subdivision
25 | * portion of the ISO
26 | * 3166-2 code.
27 | * @param names A {@link Map} from locale codes to the name in that locale.
28 | */
29 | public record Subdivision(
30 | @JacksonInject("locales")
31 | @MaxMindDbParameter(name = "locales")
32 | List locales,
33 |
34 | @JsonProperty("confidence")
35 | @MaxMindDbParameter(name = "confidence")
36 | Integer confidence,
37 |
38 | @JsonProperty("geoname_id")
39 | @MaxMindDbParameter(name = "geoname_id")
40 | Long geonameId,
41 |
42 | @JsonProperty("iso_code")
43 | @MaxMindDbParameter(name = "iso_code")
44 | String isoCode,
45 |
46 | @JsonProperty("names")
47 | @MaxMindDbParameter(name = "names")
48 | Map names
49 | ) implements NamedRecord {
50 |
51 | /**
52 | * Compact canonical constructor that ensures immutability and handles null values.
53 | */
54 | public Subdivision {
55 | locales = locales != null ? List.copyOf(locales) : List.of();
56 | names = names != null ? Map.copyOf(names) : Map.of();
57 | }
58 |
59 | /**
60 | * Constructs a {@code Subdivision} record.
61 | */
62 | public Subdivision() {
63 | this(null, null, null, null, null);
64 | }
65 |
66 | /**
67 | * Constructs an instance of {@code Subdivision} with the specified parameters.
68 | *
69 | * @param subdivision The {@code Subdivision} object to copy.
70 | * @param locales The locales to use.
71 | */
72 | public Subdivision(
73 | Subdivision subdivision,
74 | List locales
75 | ) {
76 | this(
77 | locales,
78 | subdivision.confidence(),
79 | subdivision.geonameId(),
80 | subdivision.isoCode(),
81 | subdivision.names()
82 | );
83 | }
84 |
85 | /**
86 | * @return A value from 0-100 indicating MaxMind's confidence that
87 | * the subdivision is correct. This attribute is only available from
88 | * the Insights web service and the GeoIP2 Enterprise database.
89 | * @deprecated Use {@link #confidence()} instead. This method will be removed in 6.0.0.
90 | */
91 | @Deprecated(since = "5.0.0", forRemoval = true)
92 | @JsonProperty("confidence")
93 | public Integer getConfidence() {
94 | return confidence();
95 | }
96 |
97 | /**
98 | * @return A string up to three characters long containing the
99 | * subdivision portion of the ISO
101 | * 3166-2 code.
102 | * @deprecated Use {@link #isoCode()} instead. This method will be removed in 6.0.0.
103 | */
104 | @Deprecated(since = "5.0.0", forRemoval = true)
105 | @JsonProperty("iso_code")
106 | public String getIsoCode() {
107 | return isoCode();
108 | }
109 |
110 | /**
111 | * @return The GeoName ID for the subdivision.
112 | * @deprecated Use {@link #geonameId()} instead. This method will be removed in 6.0.0.
113 | */
114 | @Deprecated(since = "5.0.0", forRemoval = true)
115 | @JsonProperty("geoname_id")
116 | public Long getGeoNameId() {
117 | return geonameId();
118 | }
119 |
120 | /**
121 | * @return The name of the subdivision based on the locales list.
122 | * @deprecated Use {@link #name()} instead. This method will be removed in 6.0.0.
123 | */
124 | @Deprecated(since = "5.0.0", forRemoval = true)
125 | @com.fasterxml.jackson.annotation.JsonIgnore
126 | public String getName() {
127 | return name();
128 | }
129 |
130 | /**
131 | * @return A {@link Map} from locale codes to the name in that locale.
132 | * @deprecated Use {@link #names()} instead. This method will be removed in 6.0.0.
133 | */
134 | @Deprecated(since = "5.0.0", forRemoval = true)
135 | @JsonProperty("names")
136 | public Map getNames() {
137 | return names();
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/record/Country.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.record;
2 |
3 | import com.fasterxml.jackson.annotation.JacksonInject;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.maxmind.db.MaxMindDbParameter;
6 | import com.maxmind.geoip2.NamedRecord;
7 | import java.util.List;
8 | import java.util.Map;
9 |
10 | /**
11 | *
12 | * Contains data for the country record associated with an IP address.
13 | *
14 | *
15 | * Do not use any of the country names as a database or map key. Use the value
16 | * returned by {@link #geonameId()} or {@link #isoCode()} instead.
17 | *
18 | *
19 | * @param locales The locales to use for retrieving localized names.
20 | * @param confidence A value from 0-100 indicating MaxMind's confidence that the
21 | * country is correct. This attribute is only available from the
22 | * Insights web service and the GeoIP2 Enterprise database.
23 | * @param geonameId The GeoName ID for the country.
24 | * @param isInEuropeanUnion This is true if the country is a member state of the
25 | * European Union.
26 | * @param isoCode The two-character ISO
27 | * 3166-1 alpha code for the country.
28 | * @param names A {@link Map} from locale codes to the name in that locale.
29 | */
30 | public record Country(
31 | @JacksonInject("locales")
32 | @MaxMindDbParameter(name = "locales")
33 | List locales,
34 |
35 | @JsonProperty("confidence")
36 | @MaxMindDbParameter(name = "confidence")
37 | Integer confidence,
38 |
39 | @JsonProperty("geoname_id")
40 | @MaxMindDbParameter(name = "geoname_id")
41 | Long geonameId,
42 |
43 | @JsonProperty("is_in_european_union")
44 | @MaxMindDbParameter(name = "is_in_european_union", useDefault = true)
45 | boolean isInEuropeanUnion,
46 |
47 | @JsonProperty("iso_code")
48 | @MaxMindDbParameter(name = "iso_code")
49 | String isoCode,
50 |
51 | @JsonProperty("names")
52 | @MaxMindDbParameter(name = "names")
53 | Map names
54 | ) implements NamedRecord {
55 |
56 | /**
57 | * Compact canonical constructor that ensures immutability and handles null values.
58 | */
59 | public Country {
60 | locales = locales != null ? List.copyOf(locales) : List.of();
61 | names = names != null ? Map.copyOf(names) : Map.of();
62 | }
63 |
64 | /**
65 | * Constructs an instance of {@code Country} with no data.
66 | */
67 | public Country() {
68 | this(null, null, null, false, null, null);
69 | }
70 |
71 | /**
72 | * Constructs an instance of {@code Country}.
73 | *
74 | * @param country The {@code Country} object to copy.
75 | * @param locales The locales to use.
76 | */
77 | public Country(
78 | Country country,
79 | List locales
80 | ) {
81 | this(
82 | locales,
83 | country.confidence(),
84 | country.geonameId(),
85 | country.isInEuropeanUnion(),
86 | country.isoCode(),
87 | country.names()
88 | );
89 | }
90 |
91 | /**
92 | * @return A value from 0-100 indicating MaxMind's confidence that the
93 | * country is correct. This attribute is only available from the
94 | * Insights web service and the GeoIP2 Enterprise database.
95 | * @deprecated Use {@link #confidence()} instead. This method will be removed in 6.0.0.
96 | */
97 | @Deprecated(since = "5.0.0", forRemoval = true)
98 | public Integer getConfidence() {
99 | return confidence();
100 | }
101 |
102 | /**
103 | * @return The two-character ISO
105 | * 3166-1 alpha code for the country.
106 | * @deprecated Use {@link #isoCode()} instead. This method will be removed in 6.0.0.
107 | */
108 | @Deprecated(since = "5.0.0", forRemoval = true)
109 | @JsonProperty("iso_code")
110 | public String getIsoCode() {
111 | return isoCode();
112 | }
113 |
114 | /**
115 | * @return The GeoName ID for the country.
116 | * @deprecated Use {@link #geonameId()} instead. This method will be removed in 6.0.0.
117 | */
118 | @Deprecated(since = "5.0.0", forRemoval = true)
119 | @JsonProperty("geoname_id")
120 | public Long getGeoNameId() {
121 | return geonameId();
122 | }
123 |
124 | /**
125 | * @return The name of the country based on the locales list.
126 | * @deprecated Use {@link #name()} instead. This method will be removed in 6.0.0.
127 | */
128 | @Deprecated(since = "5.0.0", forRemoval = true)
129 | @com.fasterxml.jackson.annotation.JsonIgnore
130 | public String getName() {
131 | return name();
132 | }
133 |
134 | /**
135 | * @return A {@link Map} from locale codes to the name in that locale.
136 | * @deprecated Use {@link #names()} instead. This method will be removed in 6.0.0.
137 | */
138 | @Deprecated(since = "5.0.0", forRemoval = true)
139 | @JsonProperty("names")
140 | public Map getNames() {
141 | return names();
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/record/Location.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.record;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.maxmind.db.MaxMindDbParameter;
5 | import com.maxmind.geoip2.JsonSerializable;
6 |
7 | /**
8 | *
9 | * Contains data for the location record associated with an IP address.
10 | *
11 | *
12 | * @param accuracyRadius The approximate accuracy radius in kilometers around the
13 | * latitude and longitude for the IP address. This is the radius
14 | * where we have a 67% confidence that the device using the IP
15 | * address resides within the circle centered at the latitude and
16 | * longitude with the provided radius.
17 | * @param averageIncome The average income in US dollars associated with the requested
18 | * IP address. This attribute is only available from the Insights
19 | * web service.
20 | * @param latitude The approximate latitude of the location associated with the IP
21 | * address. This value is not precise and should not be used to identify
22 | * a particular address or household.
23 | * @param longitude The approximate longitude of the location associated with the IP
24 | * address. This value is not precise and should not be used to identify
25 | * a particular address or household.
26 | * @param populationDensity The estimated population per square kilometer associated with
27 | * the IP address. This attribute is only available from the
28 | * Insights web service.
29 | * @param timeZone The time zone associated with location, as specified by the
30 | * IANA Time Zone Database,
31 | * e.g., "America/New_York".
32 | */
33 | public record Location(
34 | @JsonProperty("accuracy_radius")
35 | @MaxMindDbParameter(name = "accuracy_radius")
36 | Integer accuracyRadius,
37 |
38 | @JsonProperty("average_income")
39 | @MaxMindDbParameter(name = "average_income")
40 | Integer averageIncome,
41 |
42 | @JsonProperty("latitude")
43 | @MaxMindDbParameter(name = "latitude")
44 | Double latitude,
45 |
46 | @JsonProperty("longitude")
47 | @MaxMindDbParameter(name = "longitude")
48 | Double longitude,
49 |
50 | @JsonProperty("population_density")
51 | @MaxMindDbParameter(name = "population_density")
52 | Integer populationDensity,
53 |
54 | @JsonProperty("time_zone")
55 | @MaxMindDbParameter(name = "time_zone")
56 | String timeZone
57 | ) implements JsonSerializable {
58 |
59 | /**
60 | * Constructs a {@code Location} record with {@code null} values for all the fields.
61 | */
62 | public Location() {
63 | this(null, null, null, null, null, null);
64 | }
65 |
66 | /**
67 | * @return The average income in US dollars associated with the requested
68 | * IP address. This attribute is only available from the Insights web
69 | * service.
70 | * @deprecated Use {@link #averageIncome()} instead. This method will be removed in 6.0.0.
71 | */
72 | @Deprecated(since = "5.0.0", forRemoval = true)
73 | @JsonProperty("average_income")
74 | public Integer getAverageIncome() {
75 | return averageIncome();
76 | }
77 |
78 | /**
79 | * @return The estimated population per square kilometer associated with the
80 | * IP address. This attribute is only available from the Insights web
81 | * service.
82 | * @deprecated Use {@link #populationDensity()} instead. This method will be removed in 6.0.0.
83 | */
84 | @Deprecated(since = "5.0.0", forRemoval = true)
85 | @JsonProperty("population_density")
86 | public Integer getPopulationDensity() {
87 | return populationDensity();
88 | }
89 |
90 | /**
91 | * @return The time zone associated with location, as specified by the IANA Time Zone
93 | * Database, e.g., "America/New_York".
94 | * @deprecated Use {@link #timeZone()} instead. This method will be removed in 6.0.0.
95 | */
96 | @Deprecated(since = "5.0.0", forRemoval = true)
97 | @JsonProperty("time_zone")
98 | public String getTimeZone() {
99 | return timeZone();
100 | }
101 |
102 | /**
103 | * @return The approximate accuracy radius in kilometers around the
104 | * latitude and longitude for the IP address. This is the radius where we
105 | * have a 67% confidence that the device using the IP address resides
106 | * within the circle centered at the latitude and longitude with the
107 | * provided radius.
108 | * @deprecated Use {@link #accuracyRadius()} instead. This method will be removed in 6.0.0.
109 | */
110 | @Deprecated(since = "5.0.0", forRemoval = true)
111 | @JsonProperty("accuracy_radius")
112 | public Integer getAccuracyRadius() {
113 | return accuracyRadius();
114 | }
115 |
116 | /**
117 | * @return The approximate latitude of the location associated with the
118 | * IP address. This value is not precise and should not be used to
119 | * identify a particular address or household.
120 | * @deprecated Use {@link #latitude()} instead. This method will be removed in 6.0.0.
121 | */
122 | @Deprecated(since = "5.0.0", forRemoval = true)
123 | public Double getLatitude() {
124 | return latitude();
125 | }
126 |
127 | /**
128 | * @return The approximate longitude of the location associated with the
129 | * IP address. This value is not precise and should not be used to
130 | * identify a particular address or household.
131 | * @deprecated Use {@link #longitude()} instead. This method will be removed in 6.0.0.
132 | */
133 | @Deprecated(since = "5.0.0", forRemoval = true)
134 | public Double getLongitude() {
135 | return longitude();
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/test/java/com/maxmind/geoip2/model/CityResponseTest.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.model;
2 |
3 | import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
4 | import static com.github.tomakehurst.wiremock.client.WireMock.get;
5 | import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
6 | import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
7 | import static com.maxmind.geoip2.json.File.readJsonFile;
8 | import static org.junit.jupiter.api.Assertions.assertEquals;
9 | import static org.junit.jupiter.api.Assertions.assertNotNull;
10 | import static org.junit.jupiter.api.Assertions.assertNull;
11 |
12 | import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
13 | import com.github.tomakehurst.wiremock.junit5.WireMockTest;
14 | import com.maxmind.geoip2.WebServiceClient;
15 | import com.maxmind.geoip2.exception.GeoIp2Exception;
16 | import java.io.IOException;
17 | import java.net.InetAddress;
18 | import java.net.URISyntaxException;
19 | import java.util.Arrays;
20 | import java.util.Collections;
21 | import org.junit.jupiter.api.BeforeEach;
22 | import org.junit.jupiter.api.Test;
23 | import org.junit.jupiter.api.extension.RegisterExtension;
24 |
25 | // In addition to testing the CityResponse, this code exercises the locale
26 | // handling of the models
27 | @WireMockTest
28 | public class CityResponseTest {
29 | @RegisterExtension
30 | static WireMockExtension wireMock = WireMockExtension.newInstance()
31 | .options(wireMockConfig().dynamicPort().dynamicHttpsPort())
32 | .build();
33 |
34 | @BeforeEach
35 | public void createClient() throws IOException, GeoIp2Exception,
36 | URISyntaxException {
37 | wireMock.stubFor(get(urlEqualTo("/geoip/v2.1/city/1.1.1.2"))
38 | .willReturn(aResponse()
39 | .withStatus(200)
40 | .withHeader("Content-Type",
41 | "application/vnd.maxmind.com-city+json; charset=UTF-8; version=2.1")
42 | .withBody(readJsonFile("city0"))));
43 | }
44 |
45 |
46 | @Test
47 | public void testNames() throws Exception {
48 | WebServiceClient client = new WebServiceClient.Builder(6, "0123456789")
49 | .host("localhost")
50 | .port(wireMock.getPort())
51 | .disableHttps()
52 | .locales(Arrays.asList("zh-CN", "ru"))
53 | .build();
54 |
55 | CityResponse city = client.city(InetAddress.getByName("1.1.1.2"));
56 | assertEquals(
57 | "北美洲",
58 | city.continent().name(),
59 | "country.continent().name() does not return 北美洲"
60 | );
61 | assertEquals(
62 | "美国",
63 | city.country().name(),
64 | "country.country().name() does not return 美国"
65 | );
66 | assertEquals(
67 | city.country()
68 | .name(), city.country().name(),
69 | "toString() returns getName()"
70 | );
71 | }
72 |
73 | @Test
74 | public void russianFallback() throws Exception {
75 | WebServiceClient client = new WebServiceClient.Builder(42,
76 | "abcdef123456")
77 | .host("localhost")
78 | .port(wireMock.getPort())
79 | .disableHttps()
80 | .locales(Arrays.asList("as", "ru")).build();
81 |
82 | CityResponse city = client.city(InetAddress.getByName("1.1.1.2"));
83 | assertEquals(
84 | "объединяет государства",
85 | city.country().name(),
86 | "country.country().name() does not return объединяет государства"
87 | );
88 |
89 | }
90 |
91 | @Test
92 | public void testFallback() throws Exception {
93 | WebServiceClient client = new WebServiceClient.Builder(42,
94 | "abcdef123456")
95 | .host("localhost")
96 | .port(wireMock.getPort())
97 | .disableHttps()
98 | .locales(Arrays.asList("pt", "en", "zh-CN")).build();
99 | CityResponse city = client.city(InetAddress.getByName("1.1.1.2"));
100 | assertEquals(
101 | "North America",
102 | city.continent().name(),
103 | "en is returned when pt is missing"
104 | );
105 |
106 | }
107 |
108 | @Test
109 | public void noFallback() throws Exception {
110 | WebServiceClient client = new WebServiceClient.Builder(42,
111 | "abcdef123456")
112 | .host("localhost")
113 | .port(wireMock.getPort())
114 | .disableHttps()
115 | .locales(Arrays.asList("pt", "es", "af")).build();
116 | CityResponse city = client.city(InetAddress.getByName("1.1.1.2"));
117 |
118 | assertNull(
119 | city.continent().name(),
120 | "null is returned when locale is not available"
121 | );
122 | }
123 |
124 | @Test
125 | public void noLocale() throws Exception {
126 | WebServiceClient client = new WebServiceClient.Builder(42,
127 | "abcdef123456")
128 | .host("localhost")
129 | .port(wireMock.getPort())
130 | .disableHttps()
131 | .build();
132 | CityResponse city = client.city(InetAddress.getByName("1.1.1.2"));
133 | assertEquals(
134 | "North America",
135 | city.continent().name(),
136 | "en is returned when no locales are specified"
137 | );
138 |
139 | }
140 |
141 | @Test
142 | public void testMissing() throws Exception {
143 | WebServiceClient client = new WebServiceClient.Builder(42,
144 | "abcdef123456")
145 | .host("localhost")
146 | .port(wireMock.getPort())
147 | .disableHttps()
148 | .locales(Collections.singletonList("en")).build();
149 |
150 | CityResponse city = client.city(InetAddress.getByName("1.1.1.2"));
151 | assertNotNull(city.city());
152 | assertNull(city.city().name(), "null is returned when names object is missing");
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/src/test/java/com/maxmind/geoip2/model/CountryResponseTest.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.model;
2 |
3 | import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
4 | import static com.github.tomakehurst.wiremock.client.WireMock.get;
5 | import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
6 | import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
7 | import static com.maxmind.geoip2.json.File.readJsonFile;
8 | import static org.junit.jupiter.api.Assertions.assertEquals;
9 | import static org.junit.jupiter.api.Assertions.assertFalse;
10 | import static org.junit.jupiter.api.Assertions.assertTrue;
11 |
12 | import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
13 | import com.github.tomakehurst.wiremock.junit5.WireMockTest;
14 | import com.maxmind.geoip2.WebServiceClient;
15 | import com.maxmind.geoip2.exception.GeoIp2Exception;
16 | import java.io.IOException;
17 | import java.net.InetAddress;
18 | import java.net.URISyntaxException;
19 | import org.junit.jupiter.api.BeforeEach;
20 | import org.junit.jupiter.api.Test;
21 | import org.junit.jupiter.api.extension.RegisterExtension;
22 |
23 | @WireMockTest
24 | public class CountryResponseTest {
25 | @RegisterExtension
26 | static WireMockExtension wireMock = WireMockExtension.newInstance()
27 | .options(wireMockConfig().dynamicPort().dynamicHttpsPort())
28 | .build();
29 |
30 | private CountryResponse country;
31 |
32 | @BeforeEach
33 | public void createClient() throws IOException, GeoIp2Exception,
34 | URISyntaxException {
35 | wireMock.stubFor(get(urlEqualTo("/geoip/v2.1/country/1.1.1.1"))
36 | .willReturn(aResponse()
37 | .withStatus(200)
38 | .withHeader("Content-Type",
39 | "application/vnd.maxmind.com-country+json; charset=UTF-8; version=2.1")
40 | .withBody(readJsonFile("country0"))));
41 |
42 | WebServiceClient client = new WebServiceClient.Builder(6, "0123456789")
43 | .host("localhost")
44 | .port(wireMock.getPort())
45 | .disableHttps()
46 | .build();
47 |
48 | country = client.country(InetAddress.getByName("1.1.1.1"));
49 | }
50 |
51 | @Test
52 | public void testContinent() {
53 | assertEquals(
54 | "NA",
55 | this.country.continent().code(),
56 | "country.continent().code() does not return NA"
57 | );
58 | assertEquals(
59 | 42,
60 | this.country.continent().geonameId(),
61 | "country.continent().geonameId() does not return 42"
62 | );
63 | assertEquals(
64 | "North America",
65 | this.country.continent().name(),
66 | "country.continent().name() does not return North America"
67 | );
68 | }
69 |
70 | @Test
71 | public void testCountry() {
72 | assertFalse(
73 | this.country.country().isInEuropeanUnion(),
74 | "country.country().isInEuropeanUnion() does not return false"
75 | );
76 | assertEquals(
77 | this.country.country().isoCode(),
78 | "US",
79 | "country.country().code() does not return US"
80 | );
81 | assertEquals(
82 | 1,
83 | (long) this.country.country().geonameId(),
84 | "country.country().geonameId() does not return 1"
85 | );
86 | assertEquals(
87 | Integer.valueOf(56),
88 | this.country.country().confidence(),
89 | "country.country().confidence() does not return 56"
90 | );
91 | assertEquals(
92 | "United States",
93 | this.country.country().name(),
94 | "country.country().name(\"en\") does not return United States"
95 | );
96 | }
97 |
98 | @Test
99 | public void testRegisteredCountry() {
100 | assertFalse(
101 | this.country.registeredCountry().isInEuropeanUnion(),
102 | "country.registeredCountry().isInEuropeanUnion() does not return false"
103 | );
104 | assertEquals(
105 | "CA",
106 | this.country.registeredCountry().isoCode(),
107 | "country.registeredCountry().isoCode() does not return CA"
108 | );
109 | assertEquals(
110 | 2,
111 | (long) this.country.registeredCountry().geonameId(),
112 | "country.registeredCountry().geonameId() does not return 2"
113 | );
114 | assertEquals(
115 | "Canada",
116 | this.country.registeredCountry().name(),
117 | "country.registeredCountry().name(\"en\") does not return United States"
118 | );
119 | }
120 |
121 | @Test
122 | public void testRepresentedCountry() {
123 | assertTrue(
124 | this.country.representedCountry().isInEuropeanUnion(),
125 | "country.representedCountry().isInEuropeanUnion() does not return true"
126 | );
127 | assertEquals(
128 | "GB",
129 | this.country.representedCountry().isoCode(),
130 | "country.representedCountry().code() does not return GB"
131 | );
132 | assertEquals(
133 | 4,
134 | (long) this.country.representedCountry().geonameId(),
135 | "country.representedCountry().geonameId() does not return 4"
136 | );
137 | assertEquals(
138 | "United Kingdom",
139 | this.country.representedCountry().name(),
140 | "country.representedCountry().name(\"en\") does not return United Kingdom"
141 | );
142 | assertEquals(
143 | "military",
144 | this.country.representedCountry().type(),
145 | "country.representedCountry().type() does not return military"
146 | );
147 | }
148 |
149 | @Test
150 | public void testTraits() {
151 |
152 | assertEquals(
153 | "1.2.3.4",
154 | this.country.traits().ipAddress().getHostAddress(),
155 | "country.traits().getIpAddress does not return 1.2.3.4"
156 | );
157 |
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/record/RepresentedCountry.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.record;
2 |
3 | import com.fasterxml.jackson.annotation.JacksonInject;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.maxmind.db.MaxMindDbParameter;
6 | import com.maxmind.geoip2.NamedRecord;
7 | import java.util.List;
8 | import java.util.Map;
9 |
10 | /**
11 | *
12 | * Contains data for the represented country associated with an IP address.
13 | *
14 | *
15 | * This class contains the country-level data associated with an IP address for
16 | * the IP's represented country. The represented country is the country
17 | * represented by something like a military base.
18 | *
19 | *
20 | * Do not use any of the country names as a database or map key. Use the value
21 | * returned by {@link #geonameId()} or {@link #isoCode()} instead.
22 | *
23 | *
24 | * @param locales The locales to use for retrieving localized names.
25 | * @param confidence A value from 0-100 indicating MaxMind's confidence that the
26 | * country is correct. This attribute is only available from the
27 | * Insights web service and the GeoIP2 Enterprise database.
28 | * @param geonameId The GeoName ID for the country.
29 | * @param isInEuropeanUnion This is true if the country is a member state of the
30 | * European Union.
31 | * @param isoCode The two-character ISO
32 | * 3166-1 alpha code for the country.
33 | * @param names A {@link Map} from locale codes to the name in that locale.
34 | * @param type A string indicating the type of entity that is representing the
35 | * country. Currently, we only return {@code military} but this could
36 | * expand to include other types in the future.
37 | */
38 | public record RepresentedCountry(
39 | @JacksonInject("locales")
40 | @MaxMindDbParameter(name = "locales")
41 | List locales,
42 |
43 | @JsonProperty("confidence")
44 | @MaxMindDbParameter(name = "confidence")
45 | Integer confidence,
46 |
47 | @JsonProperty("geoname_id")
48 | @MaxMindDbParameter(name = "geoname_id")
49 | Long geonameId,
50 |
51 | @JsonProperty("is_in_european_union")
52 | @MaxMindDbParameter(name = "is_in_european_union", useDefault = true)
53 | boolean isInEuropeanUnion,
54 |
55 | @JsonProperty("iso_code")
56 | @MaxMindDbParameter(name = "iso_code")
57 | String isoCode,
58 |
59 | @JsonProperty("names")
60 | @MaxMindDbParameter(name = "names")
61 | Map names,
62 |
63 | @JsonProperty("type")
64 | @MaxMindDbParameter(name = "type")
65 | String type
66 | ) implements NamedRecord {
67 |
68 | /**
69 | * Compact canonical constructor that ensures immutability and handles null values.
70 | */
71 | public RepresentedCountry {
72 | locales = locales != null ? List.copyOf(locales) : List.of();
73 | names = names != null ? Map.copyOf(names) : Map.of();
74 | }
75 |
76 | /**
77 | * Constructs an instance of {@code RepresentedCountry} with no data.
78 | */
79 | public RepresentedCountry() {
80 | this(null, null, null, false, null, null, null);
81 | }
82 |
83 | /**
84 | * Constructs an instance of {@code RepresentedCountry}.
85 | *
86 | * @param country The {@code RepresentedCountry} object to copy.
87 | * @param locales The locales to use.
88 | */
89 | public RepresentedCountry(
90 | RepresentedCountry country,
91 | List locales
92 | ) {
93 | this(
94 | locales,
95 | country.confidence(),
96 | country.geonameId(),
97 | country.isInEuropeanUnion(),
98 | country.isoCode(),
99 | country.names(),
100 | country.type()
101 | );
102 | }
103 |
104 | /**
105 | * @return A string indicating the type of entity that is representing the
106 | * country. Currently, we only return {@code military} but this could
107 | * expand to include other types in the future.
108 | * @deprecated Use {@link #type()} instead. This method will be removed in 6.0.0.
109 | */
110 | @Deprecated(since = "5.0.0", forRemoval = true)
111 | public String getType() {
112 | return type();
113 | }
114 |
115 | /**
116 | * @return A value from 0-100 indicating MaxMind's confidence that the
117 | * country is correct. This attribute is only available from the
118 | * Insights web service and the GeoIP2 Enterprise database.
119 | * @deprecated Use {@link #confidence()} instead. This method will be removed in 6.0.0.
120 | */
121 | @Deprecated(since = "5.0.0", forRemoval = true)
122 | public Integer getConfidence() {
123 | return confidence();
124 | }
125 |
126 | /**
127 | * @return The two-character ISO
129 | * 3166-1 alpha code for the country.
130 | * @deprecated Use {@link #isoCode()} instead. This method will be removed in 6.0.0.
131 | */
132 | @Deprecated(since = "5.0.0", forRemoval = true)
133 | @JsonProperty("iso_code")
134 | public String getIsoCode() {
135 | return isoCode();
136 | }
137 |
138 | /**
139 | * @return The GeoName ID for the country.
140 | * @deprecated Use {@link #geonameId()} instead. This method will be removed in 6.0.0.
141 | */
142 | @Deprecated(since = "5.0.0", forRemoval = true)
143 | @JsonProperty("geoname_id")
144 | public Long getGeoNameId() {
145 | return geonameId();
146 | }
147 |
148 | /**
149 | * @return The name of the country based on the locales list.
150 | * @deprecated Use {@link #name()} instead. This method will be removed in 6.0.0.
151 | */
152 | @Deprecated(since = "5.0.0", forRemoval = true)
153 | @com.fasterxml.jackson.annotation.JsonIgnore
154 | public String getName() {
155 | return name();
156 | }
157 |
158 | /**
159 | * @return A {@link Map} from locale codes to the name in that locale.
160 | * @deprecated Use {@link #names()} instead. This method will be removed in 6.0.0.
161 | */
162 | @Deprecated(since = "5.0.0", forRemoval = true)
163 | @JsonProperty("names")
164 | public Map getNames() {
165 | return names();
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/model/CountryResponse.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.maxmind.db.MaxMindDbParameter;
5 | import com.maxmind.geoip2.JsonSerializable;
6 | import com.maxmind.geoip2.record.Continent;
7 | import com.maxmind.geoip2.record.Country;
8 | import com.maxmind.geoip2.record.MaxMind;
9 | import com.maxmind.geoip2.record.RepresentedCountry;
10 | import com.maxmind.geoip2.record.Traits;
11 | import java.util.List;
12 |
13 | /**
14 | * This class provides a model for the data returned by the Country web service
15 | * and the Country database.
16 | *
17 | * @param continent Continent record for the requested IP address.
18 | * @param country Country record for the requested IP address. This object represents the country
19 | * where MaxMind believes the end user is located.
20 | * @param maxmind MaxMind record containing data related to your account.
21 | * @param registeredCountry Registered country record for the requested IP address. This record
22 | * represents the country where the ISP has registered a given IP block
23 | * and may differ from the user's country.
24 | * @param representedCountry Represented country record for the requested IP address. The
25 | * represented country is used for things like military bases. It is
26 | * only present when the represented country differs from the country.
27 | * @param traits Record for the traits of the requested IP address.
28 | * @see GeoIP2 Web
29 | * Services
30 | */
31 | public record CountryResponse(
32 | @JsonProperty("continent")
33 | @MaxMindDbParameter(name = "continent")
34 | Continent continent,
35 |
36 | @JsonProperty("country")
37 | @MaxMindDbParameter(name = "country")
38 | Country country,
39 |
40 | @JsonProperty("maxmind")
41 | @MaxMindDbParameter(name = "maxmind")
42 | MaxMind maxmind,
43 |
44 | @JsonProperty("registered_country")
45 | @MaxMindDbParameter(name = "registered_country")
46 | Country registeredCountry,
47 |
48 | @JsonProperty("represented_country")
49 | @MaxMindDbParameter(name = "represented_country")
50 | RepresentedCountry representedCountry,
51 |
52 | @JsonProperty("traits")
53 | @MaxMindDbParameter(name = "traits")
54 | Traits traits
55 | ) implements JsonSerializable {
56 |
57 | /**
58 | * Compact canonical constructor that sets defaults for null values.
59 | */
60 | public CountryResponse {
61 | continent = continent != null ? continent : new Continent();
62 | country = country != null ? country : new Country();
63 | maxmind = maxmind != null ? maxmind : new MaxMind();
64 | registeredCountry = registeredCountry != null ? registeredCountry : new Country();
65 | representedCountry = representedCountry != null
66 | ? representedCountry : new RepresentedCountry();
67 | traits = traits != null ? traits : new Traits();
68 | }
69 |
70 | /**
71 | * Constructs an instance of {@code CountryResponse} with the specified parameters.
72 | *
73 | * @param response the response
74 | * @param locales the locales
75 | */
76 | public CountryResponse(
77 | CountryResponse response,
78 | List locales
79 | ) {
80 | this(
81 | new Continent(response.continent(), locales),
82 | new Country(response.country(), locales),
83 | response.maxmind(),
84 | new Country(response.registeredCountry(), locales),
85 | new RepresentedCountry(response.representedCountry(), locales),
86 | response.traits()
87 | );
88 | }
89 |
90 | /**
91 | * @return MaxMind record containing data related to your account.
92 | * @deprecated Use {@link #maxmind()} instead. This method will be removed in 6.0.0.
93 | */
94 | @Deprecated(since = "5.0.0", forRemoval = true)
95 | @JsonProperty("maxmind")
96 | public MaxMind getMaxMind() {
97 | return maxmind();
98 | }
99 |
100 | /**
101 | * @return Registered country record for the requested IP address. This
102 | * record represents the country where the ISP has registered a
103 | * given IP block and may differ from the user's country.
104 | * @deprecated Use {@link #registeredCountry()} instead. This method will be removed in 6.0.0.
105 | */
106 | @Deprecated(since = "5.0.0", forRemoval = true)
107 | @JsonProperty("registered_country")
108 | public Country getRegisteredCountry() {
109 | return registeredCountry();
110 | }
111 |
112 | /**
113 | * @return Continent record for the requested IP address.
114 | * @deprecated Use {@link #continent()} instead. This method will be removed in 6.0.0.
115 | */
116 | @Deprecated(since = "5.0.0", forRemoval = true)
117 | public Continent getContinent() {
118 | return continent();
119 | }
120 |
121 | /**
122 | * @return Country record for the requested IP address. This object
123 | * represents the country where MaxMind believes the end user is
124 | * located.
125 | * @deprecated Use {@link #country()} instead. This method will be removed in 6.0.0.
126 | */
127 | @Deprecated(since = "5.0.0", forRemoval = true)
128 | public Country getCountry() {
129 | return country();
130 | }
131 |
132 | /**
133 | * @return Represented country record for the requested IP address. The
134 | * represented country is used for things like military bases. It is
135 | * only present when the represented country differs from the
136 | * country.
137 | * @deprecated Use {@link #representedCountry()} instead. This method will be removed in 6.0.0.
138 | */
139 | @Deprecated(since = "5.0.0", forRemoval = true)
140 | @JsonProperty("represented_country")
141 | public RepresentedCountry getRepresentedCountry() {
142 | return representedCountry();
143 | }
144 |
145 | /**
146 | * @return Record for the traits of the requested IP address.
147 | * @deprecated Use {@link #traits()} instead. This method will be removed in 6.0.0.
148 | */
149 | @Deprecated(since = "5.0.0", forRemoval = true)
150 | public Traits getTraits() {
151 | return traits();
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/model/IspResponse.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
5 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
6 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
7 | import com.maxmind.db.MaxMindDbIpAddress;
8 | import com.maxmind.db.MaxMindDbNetwork;
9 | import com.maxmind.db.MaxMindDbParameter;
10 | import com.maxmind.db.Network;
11 | import com.maxmind.geoip2.JsonSerializable;
12 | import com.maxmind.geoip2.NetworkDeserializer;
13 | import java.net.InetAddress;
14 |
15 | /**
16 | * This class provides the GeoIP2 ISP model.
17 | *
18 | * @param autonomousSystemNumber The autonomous system number associated with the IP address.
19 | * @param autonomousSystemOrganization The organization associated with the registered autonomous
20 | * system number for the IP address.
21 | * @param ipAddress The IP address that the data in the model is for.
22 | * @param isp The name of the ISP associated with the IP address.
23 | * @param mobileCountryCode The
24 | * mobile country code (MCC) associated with the IP address and ISP.
25 | * This property is available from the City and Insights web services and
26 | * the GeoIP2 Enterprise database.
27 | * @param mobileNetworkCode The
28 | * mobile network code (MNC) associated with the IP address and ISP.
29 | * This property is available from the City and Insights web services and
30 | * the GeoIP2 Enterprise database.
31 | * @param organization The name of the organization associated with the IP address.
32 | * @param network The network associated with the record. In particular, this is the largest
33 | * network where all the fields besides IP address have the same value.
34 | */
35 | public record IspResponse(
36 | @JsonProperty("autonomous_system_number")
37 | @MaxMindDbParameter(name = "autonomous_system_number")
38 | Long autonomousSystemNumber,
39 |
40 | @JsonProperty("autonomous_system_organization")
41 | @MaxMindDbParameter(name = "autonomous_system_organization")
42 | String autonomousSystemOrganization,
43 |
44 | @JsonProperty("ip_address")
45 | @MaxMindDbIpAddress
46 | InetAddress ipAddress,
47 |
48 | @JsonProperty("isp")
49 | @MaxMindDbParameter(name = "isp")
50 | String isp,
51 |
52 | @JsonProperty("mobile_country_code")
53 | @MaxMindDbParameter(name = "mobile_country_code")
54 | String mobileCountryCode,
55 |
56 | @JsonProperty("mobile_network_code")
57 | @MaxMindDbParameter(name = "mobile_network_code")
58 | String mobileNetworkCode,
59 |
60 | @JsonProperty("organization")
61 | @MaxMindDbParameter(name = "organization")
62 | String organization,
63 |
64 | @JsonProperty("network")
65 | @JsonDeserialize(using = NetworkDeserializer.class)
66 | @MaxMindDbNetwork
67 | Network network
68 | ) implements JsonSerializable {
69 |
70 | /**
71 | * @return The autonomous system number associated with the IP address.
72 | * @deprecated Use {@link #autonomousSystemNumber()} instead. This method will be removed
73 | * in 6.0.0.
74 | */
75 | @Deprecated(since = "5.0.0", forRemoval = true)
76 | @JsonProperty("autonomous_system_number")
77 | public Long getAutonomousSystemNumber() {
78 | return autonomousSystemNumber();
79 | }
80 |
81 | /**
82 | * @return The organization associated with the registered autonomous system
83 | * number for the IP address
84 | * @deprecated Use {@link #autonomousSystemOrganization()} instead. This method will be
85 | * removed in 6.0.0.
86 | */
87 | @Deprecated(since = "5.0.0", forRemoval = true)
88 | @JsonProperty("autonomous_system_organization")
89 | public String getAutonomousSystemOrganization() {
90 | return autonomousSystemOrganization();
91 | }
92 |
93 | /**
94 | * @return The IP address that the data in the model is for.
95 | * @deprecated Use {@link #ipAddress()} instead. This method will be removed in 6.0.0.
96 | */
97 | @Deprecated(since = "5.0.0", forRemoval = true)
98 | @JsonProperty("ip_address")
99 | public String getIpAddress() {
100 | return ipAddress().getHostAddress();
101 | }
102 |
103 | /**
104 | * @return The name of the ISP associated with the IP address.
105 | * @deprecated Use {@link #isp()} instead. This method will be removed in 6.0.0.
106 | */
107 | @Deprecated(since = "5.0.0", forRemoval = true)
108 | public String getIsp() {
109 | return isp();
110 | }
111 |
112 | /**
113 | * @return The
114 | * mobile country code (MCC) associated with the IP address and ISP.
115 | * This property is available from the City and Insights web services and
116 | * the GeoIP2 Enterprise database.
117 | * @deprecated Use {@link #mobileCountryCode()} instead. This method will be removed in 6.0.0.
118 | */
119 | @Deprecated(since = "5.0.0", forRemoval = true)
120 | @JsonProperty("mobile_country_code")
121 | public String getMobileCountryCode() {
122 | return mobileCountryCode();
123 | }
124 |
125 | /**
126 | * @return The
127 | * mobile network code (MNC) associated with the IP address and ISP.
128 | * This property is available from the City and Insights web services and
129 | * the GeoIP2 Enterprise database.
130 | * @deprecated Use {@link #mobileNetworkCode()} instead. This method will be removed in 6.0.0.
131 | */
132 | @Deprecated(since = "5.0.0", forRemoval = true)
133 | @JsonProperty("mobile_network_code")
134 | public String getMobileNetworkCode() {
135 | return mobileNetworkCode();
136 | }
137 |
138 | /**
139 | * @return The name of the organization associated with the IP address.
140 | * @deprecated Use {@link #organization()} instead. This method will be removed in 6.0.0.
141 | */
142 | @Deprecated(since = "5.0.0", forRemoval = true)
143 | public String getOrganization() {
144 | return organization();
145 | }
146 |
147 | /**
148 | * @return The network associated with the record. In particular, this is
149 | * the largest network where all the fields besides IP address have the
150 | * same value.
151 | * @deprecated Use {@link #network()} instead. This method will be removed in 6.0.0.
152 | */
153 | @Deprecated(since = "5.0.0", forRemoval = true)
154 | @JsonProperty
155 | @JsonSerialize(using = ToStringSerializer.class)
156 | public Network getNetwork() {
157 | return network();
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/model/AnonymousPlusResponse.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
5 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
6 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
7 | import com.maxmind.db.MaxMindDbConstructor;
8 | import com.maxmind.db.MaxMindDbIpAddress;
9 | import com.maxmind.db.MaxMindDbNetwork;
10 | import com.maxmind.db.MaxMindDbParameter;
11 | import com.maxmind.db.Network;
12 | import com.maxmind.geoip2.JsonSerializable;
13 | import com.maxmind.geoip2.NetworkDeserializer;
14 | import java.net.InetAddress;
15 | import java.time.LocalDate;
16 |
17 | /**
18 | * This class provides the GeoIP Anonymous Plus model.
19 | *
20 | * @param ipAddress The IP address that the data in the model is for.
21 | * @param isAnonymous Whether the IP address belongs to any sort of anonymous network.
22 | * @param isAnonymousVpn Whether the IP address is registered to an anonymous VPN provider. If a
23 | * VPN provider does not register subnets under names associated with them,
24 | * we will likely only flag their IP ranges using isHostingProvider.
25 | * @param isHostingProvider Whether the IP address belongs to a hosting or VPN provider (see
26 | * description of isAnonymousVpn).
27 | * @param isPublicProxy Whether the IP address belongs to a public proxy.
28 | * @param isResidentialProxy Whether the IP address is on a suspected anonymizing network and
29 | * belongs to a residential ISP.
30 | * @param isTorExitNode Whether the IP address is a Tor exit node.
31 | * @param network The network associated with the record. In particular, this is the largest
32 | * network where all the fields besides IP address have the same value.
33 | * @param anonymizerConfidence A score ranging from 1 to 99 that is our percent confidence that
34 | * the network is currently part of an actively used VPN service.
35 | * @param networkLastSeen The last day that the network was sighted in our analysis of anonymized
36 | * networks.
37 | * @param providerName The name of the VPN provider (e.g., NordVPN, SurfShark, etc.) associated
38 | * with the network.
39 | */
40 | public record AnonymousPlusResponse(
41 | @JsonProperty("ip_address")
42 | @MaxMindDbIpAddress
43 | InetAddress ipAddress,
44 |
45 | @JsonProperty("is_anonymous")
46 | @MaxMindDbParameter(name = "is_anonymous", useDefault = true)
47 | boolean isAnonymous,
48 |
49 | @JsonProperty("is_anonymous_vpn")
50 | @MaxMindDbParameter(name = "is_anonymous_vpn", useDefault = true)
51 | boolean isAnonymousVpn,
52 |
53 | @JsonProperty("is_hosting_provider")
54 | @MaxMindDbParameter(name = "is_hosting_provider", useDefault = true)
55 | boolean isHostingProvider,
56 |
57 | @JsonProperty("is_public_proxy")
58 | @MaxMindDbParameter(name = "is_public_proxy", useDefault = true)
59 | boolean isPublicProxy,
60 |
61 | @JsonProperty("is_residential_proxy")
62 | @MaxMindDbParameter(name = "is_residential_proxy", useDefault = true)
63 | boolean isResidentialProxy,
64 |
65 | @JsonProperty("is_tor_exit_node")
66 | @MaxMindDbParameter(name = "is_tor_exit_node", useDefault = true)
67 | boolean isTorExitNode,
68 |
69 | @JsonProperty("network")
70 | @JsonDeserialize(using = NetworkDeserializer.class)
71 | @MaxMindDbNetwork
72 | Network network,
73 |
74 | @JsonProperty("anonymizer_confidence")
75 | @MaxMindDbParameter(name = "anonymizer_confidence")
76 | Integer anonymizerConfidence,
77 |
78 | @JsonProperty("network_last_seen")
79 | @MaxMindDbParameter(name = "network_last_seen")
80 | LocalDate networkLastSeen,
81 |
82 | @JsonProperty("provider_name")
83 | @MaxMindDbParameter(name = "provider_name")
84 | String providerName
85 | ) implements JsonSerializable {
86 |
87 | /**
88 | * Constructs an instance of {@code AnonymousPlusResponse} with date parsing
89 | * from MaxMind database.
90 | *
91 | * @param ipAddress the IP address being checked
92 | * @param isAnonymous whether the IP address belongs to any sort of anonymous network
93 | * @param isAnonymousVpn whether the IP address belongs to an anonymous VPN system
94 | * @param isHostingProvider whether the IP address belongs to a hosting provider
95 | * @param isPublicProxy whether the IP address belongs to a public proxy system
96 | * @param isResidentialProxy whether the IP address belongs to a residential proxy system
97 | * @param isTorExitNode whether the IP address is a Tor exit node
98 | * @param network the network associated with the record
99 | * @param anonymizerConfidence confidence that the network is a VPN.
100 | * @param networkLastSeen the last sighting of the network.
101 | * @param providerName the name of the VPN provider.
102 | */
103 | @MaxMindDbConstructor
104 | public AnonymousPlusResponse(
105 | @MaxMindDbIpAddress InetAddress ipAddress,
106 | @MaxMindDbParameter(name = "is_anonymous", useDefault = true)
107 | boolean isAnonymous,
108 | @MaxMindDbParameter(name = "is_anonymous_vpn", useDefault = true)
109 | boolean isAnonymousVpn,
110 | @MaxMindDbParameter(name = "is_hosting_provider", useDefault = true)
111 | boolean isHostingProvider,
112 | @MaxMindDbParameter(name = "is_public_proxy", useDefault = true)
113 | boolean isPublicProxy,
114 | @MaxMindDbParameter(name = "is_residential_proxy", useDefault = true)
115 | boolean isResidentialProxy,
116 | @MaxMindDbParameter(name = "is_tor_exit_node", useDefault = true)
117 | boolean isTorExitNode,
118 | @MaxMindDbNetwork Network network,
119 | @MaxMindDbParameter(name = "anonymizer_confidence") Integer anonymizerConfidence,
120 | @MaxMindDbParameter(name = "network_last_seen") String networkLastSeen,
121 | @MaxMindDbParameter(name = "provider_name") String providerName
122 | ) {
123 | this(
124 | ipAddress,
125 | isAnonymous,
126 | isAnonymousVpn,
127 | isHostingProvider,
128 | isPublicProxy,
129 | isResidentialProxy,
130 | isTorExitNode,
131 | network,
132 | anonymizerConfidence,
133 | networkLastSeen != null ? LocalDate.parse(networkLastSeen) : null,
134 | providerName
135 | );
136 | }
137 |
138 | /**
139 | * @return The IP address that the data in the model is for.
140 | * @deprecated Use {@link #ipAddress()} instead. This method will be removed in 6.0.0.
141 | */
142 | @Deprecated(since = "5.0.0", forRemoval = true)
143 | @JsonProperty("ip_address")
144 | public String getIpAddress() {
145 | return ipAddress().getHostAddress();
146 | }
147 |
148 | /**
149 | * @return The network associated with the record. In particular, this is
150 | * the largest network where all the fields besides IP address have the
151 | * same value.
152 | * @deprecated Use {@link #network()} instead. This method will be removed in 6.0.0.
153 | */
154 | @Deprecated(since = "5.0.0", forRemoval = true)
155 | @JsonProperty
156 | @JsonSerialize(using = ToStringSerializer.class)
157 | public Network getNetwork() {
158 | return network();
159 | }
160 |
161 | /**
162 | * @return A score ranging from 1 to 99 that is our percent confidence that the network is
163 | * currently part of an actively used VPN service.
164 | * @deprecated Use {@link #anonymizerConfidence()} instead. This method will be removed
165 | * in 6.0.0.
166 | */
167 | @Deprecated(since = "5.0.0", forRemoval = true)
168 | @JsonProperty
169 | public Integer getAnonymizerConfidence() {
170 | return anonymizerConfidence();
171 | }
172 |
173 | /**
174 | * @return The last day that the network was sighted in our analysis of anonymized networks.
175 | * @deprecated Use {@link #networkLastSeen()} instead. This method will be removed in 6.0.0.
176 | */
177 | @Deprecated(since = "5.0.0", forRemoval = true)
178 | @JsonProperty
179 | public LocalDate getNetworkLastSeen() {
180 | return networkLastSeen();
181 | }
182 |
183 | /**
184 | * @return The name of the VPN provider (e.g., NordVPN, SurfShark, etc.) associated with the
185 | * network.
186 | * @deprecated Use {@link #providerName()} instead. This method will be removed in 6.0.0.
187 | */
188 | @Deprecated(since = "5.0.0", forRemoval = true)
189 | @JsonProperty
190 | public String getProviderName() {
191 | return providerName();
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/DatabaseProvider.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2;
2 |
3 | import com.maxmind.geoip2.exception.GeoIp2Exception;
4 | import com.maxmind.geoip2.model.AnonymousIpResponse;
5 | import com.maxmind.geoip2.model.AnonymousPlusResponse;
6 | import com.maxmind.geoip2.model.AsnResponse;
7 | import com.maxmind.geoip2.model.CityResponse;
8 | import com.maxmind.geoip2.model.ConnectionTypeResponse;
9 | import com.maxmind.geoip2.model.CountryResponse;
10 | import com.maxmind.geoip2.model.DomainResponse;
11 | import com.maxmind.geoip2.model.EnterpriseResponse;
12 | import com.maxmind.geoip2.model.IpRiskResponse;
13 | import com.maxmind.geoip2.model.IspResponse;
14 | import java.io.IOException;
15 | import java.net.InetAddress;
16 | import java.util.Optional;
17 |
18 | /**
19 | * Interface for GeoIP2 database providers.
20 | */
21 | public interface DatabaseProvider extends GeoIp2Provider {
22 |
23 | /**
24 | * @param ipAddress IPv4 or IPv6 address to lookup.
25 | * @return A Country model for the requested IP address or empty if it is not in the DB.
26 | * @throws GeoIp2Exception if there is an error looking up the IP
27 | * @throws IOException if there is an IO error
28 | */
29 | Optional tryCountry(InetAddress ipAddress) throws IOException,
30 | GeoIp2Exception;
31 |
32 | /**
33 | * @param ipAddress IPv4 or IPv6 address to lookup.
34 | * @return A City model for the requested IP address or empty if it is not in the DB.
35 | * @throws GeoIp2Exception if there is an error looking up the IP
36 | * @throws IOException if there is an IO error
37 | */
38 | Optional tryCity(InetAddress ipAddress) throws IOException,
39 | GeoIp2Exception;
40 |
41 | /**
42 | * Look up an IP address in a GeoIP2 Anonymous IP.
43 | *
44 | * @param ipAddress IPv4 or IPv6 address to lookup.
45 | * @return a AnonymousIpResponse for the requested IP address.
46 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
47 | * @throws java.io.IOException if there is an IO error
48 | */
49 | AnonymousIpResponse anonymousIp(InetAddress ipAddress) throws IOException,
50 | GeoIp2Exception;
51 |
52 | /**
53 | * Look up an IP address in a GeoIP2 Anonymous IP.
54 | *
55 | * @param ipAddress IPv4 or IPv6 address to lookup.
56 | * @return a AnonymousIpResponse for the requested IP address or empty if it is not in the DB.
57 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
58 | * @throws java.io.IOException if there is an IO error
59 | */
60 | Optional tryAnonymousIp(InetAddress ipAddress) throws IOException,
61 | GeoIp2Exception;
62 |
63 | /**
64 | * Look up an IP address in a GeoIP2 Anonymous Plus.
65 | *
66 | * @param ipAddress IPv4 or IPv6 address to lookup.
67 | * @return a AnonymousPlusResponse for the requested IP address.
68 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
69 | * @throws java.io.IOException if there is an IO error
70 | */
71 | AnonymousPlusResponse anonymousPlus(InetAddress ipAddress) throws IOException,
72 | GeoIp2Exception;
73 |
74 | /**
75 | * Look up an IP address in a GeoIP2 Anonymous Plus.
76 | *
77 | * @param ipAddress IPv4 or IPv6 address to lookup.
78 | * @return a AnonymousPlusResponse for the requested IP address or empty if it is not in the DB.
79 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
80 | * @throws java.io.IOException if there is an IO error
81 | */
82 | Optional tryAnonymousPlus(InetAddress ipAddress) throws IOException,
83 | GeoIp2Exception;
84 |
85 | /**
86 | * Look up an IP address in a GeoIP2 IP Risk database.
87 | *
88 | * @param ipAddress IPv4 or IPv6 address to lookup.
89 | * @return an IpRiskResponse for the requested IP address.
90 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
91 | * @throws java.io.IOException if there is an IO error
92 | */
93 | IpRiskResponse ipRisk(InetAddress ipAddress) throws IOException,
94 | GeoIp2Exception;
95 |
96 | /**
97 | * Look up an IP address in a GeoIP2 IP Risk database.
98 | *
99 | * @param ipAddress IPv4 or IPv6 address to lookup.
100 | * @return an IPRiskResponse for the requested IP address or empty if it is not in the DB.
101 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
102 | * @throws java.io.IOException if there is an IO error
103 | */
104 | Optional tryIpRisk(InetAddress ipAddress) throws IOException,
105 | GeoIp2Exception;
106 |
107 | /**
108 | * Look up an IP address in a GeoLite2 ASN database.
109 | *
110 | * @param ipAddress IPv4 or IPv6 address to lookup.
111 | * @return an IspResponse for the requested IP address.
112 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
113 | * @throws java.io.IOException if there is an IO error
114 | */
115 | AsnResponse asn(InetAddress ipAddress) throws IOException,
116 | GeoIp2Exception;
117 |
118 | /**
119 | * Look up an IP address in a GeoLite2 ASN database.
120 | *
121 | * @param ipAddress IPv4 or IPv6 address to lookup.
122 | * @return an IspResponse for the requested IP address or empty if it is not in the DB.
123 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
124 | * @throws java.io.IOException if there is an IO error
125 | */
126 | Optional tryAsn(InetAddress ipAddress) throws IOException,
127 | GeoIp2Exception;
128 |
129 | /**
130 | * Look up an IP address in a GeoIP2 Connection Type database.
131 | *
132 | * @param ipAddress IPv4 or IPv6 address to lookup.
133 | * @return a ConnectTypeResponse for the requested IP address.
134 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
135 | * @throws java.io.IOException if there is an IO error
136 | */
137 | ConnectionTypeResponse connectionType(InetAddress ipAddress)
138 | throws IOException, GeoIp2Exception;
139 |
140 | /**
141 | * Look up an IP address in a GeoIP2 Connection Type database.
142 | *
143 | * @param ipAddress IPv4 or IPv6 address to lookup.
144 | * @return a ConnectTypeResponse for the requested IP address or empty if it is not in the DB.
145 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
146 | * @throws java.io.IOException if there is an IO error
147 | */
148 | Optional tryConnectionType(InetAddress ipAddress)
149 | throws IOException, GeoIp2Exception;
150 |
151 | /**
152 | * Look up an IP address in a GeoIP2 Domain database.
153 | *
154 | * @param ipAddress IPv4 or IPv6 address to lookup.
155 | * @return a DomainResponse for the requested IP address.
156 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
157 | * @throws java.io.IOException if there is an IO error
158 | */
159 | DomainResponse domain(InetAddress ipAddress) throws IOException,
160 | GeoIp2Exception;
161 |
162 | /**
163 | * Look up an IP address in a GeoIP2 Domain database.
164 | *
165 | * @param ipAddress IPv4 or IPv6 address to lookup.
166 | * @return a DomainResponse for the requested IP address or empty if it is not in the DB.
167 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
168 | * @throws java.io.IOException if there is an IO error
169 | */
170 | Optional tryDomain(InetAddress ipAddress) throws IOException,
171 | GeoIp2Exception;
172 |
173 | /**
174 | * Look up an IP address in a GeoIP2 Enterprise database.
175 | *
176 | * @param ipAddress IPv4 or IPv6 address to lookup.
177 | * @return an EnterpriseResponse for the requested IP address.
178 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
179 | * @throws java.io.IOException if there is an IO error
180 | */
181 | EnterpriseResponse enterprise(InetAddress ipAddress) throws IOException,
182 | GeoIp2Exception;
183 |
184 | /**
185 | * Look up an IP address in a GeoIP2 Enterprise database.
186 | *
187 | * @param ipAddress IPv4 or IPv6 address to lookup.
188 | * @return an EnterpriseResponse for the requested IP address or empty if it is not in the DB.
189 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
190 | * @throws java.io.IOException if there is an IO error
191 | */
192 | Optional tryEnterprise(InetAddress ipAddress) throws IOException,
193 | GeoIp2Exception;
194 |
195 | /**
196 | * Look up an IP address in a GeoIP2 ISP database.
197 | *
198 | * @param ipAddress IPv4 or IPv6 address to lookup.
199 | * @return an IspResponse for the requested IP address.
200 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
201 | * @throws java.io.IOException if there is an IO error
202 | */
203 | IspResponse isp(InetAddress ipAddress) throws IOException,
204 | GeoIp2Exception;
205 |
206 | /**
207 | * Look up an IP address in a GeoIP2 ISP database.
208 | *
209 | * @param ipAddress IPv4 or IPv6 address to look up or empty if it is not in the DB.
210 | * @return an IspResponse for the requested IP address.
211 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP
212 | * @throws java.io.IOException if there is an IO error
213 | */
214 | Optional tryIsp(InetAddress ipAddress) throws IOException,
215 | GeoIp2Exception;
216 | }
217 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/model/InsightsResponse.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnore;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.maxmind.geoip2.JsonSerializable;
6 | import com.maxmind.geoip2.record.Anonymizer;
7 | import com.maxmind.geoip2.record.City;
8 | import com.maxmind.geoip2.record.Continent;
9 | import com.maxmind.geoip2.record.Country;
10 | import com.maxmind.geoip2.record.Location;
11 | import com.maxmind.geoip2.record.MaxMind;
12 | import com.maxmind.geoip2.record.Postal;
13 | import com.maxmind.geoip2.record.RepresentedCountry;
14 | import com.maxmind.geoip2.record.Subdivision;
15 | import com.maxmind.geoip2.record.Traits;
16 | import java.util.ArrayList;
17 | import java.util.List;
18 |
19 | /**
20 | * This class provides a model for the data returned by the Insights web
21 | * service.
22 | *
23 | * @param anonymizer Anonymizer record for the requested IP address. This contains information
24 | * about whether the IP address belongs to an anonymizing network such as a VPN,
25 | * proxy, or Tor exit node.
26 | * @param city City record for the requested IP address.
27 | * @param continent Continent record for the requested IP address.
28 | * @param country Country record for the requested IP address. This object represents the country
29 | * where MaxMind believes the end user is located.
30 | * @param location Location record for the requested IP address.
31 | * @param maxmind MaxMind record containing data related to your account.
32 | * @param postal Postal record for the requested IP address.
33 | * @param registeredCountry Registered country record for the requested IP address. This record
34 | * represents the country where the ISP has registered a given IP block
35 | * and may differ from the user's country.
36 | * @param representedCountry Represented country record for the requested IP address. The
37 | * represented country is used for things like military bases. It is
38 | * only present when the represented country differs from the country.
39 | * @param subdivisions An {@link List} of {@link Subdivision} objects representing the country
40 | * subdivisions for the requested IP address. The number and type of
41 | * subdivisions varies by country, but a subdivision is typically a state,
42 | * province, county, etc. Subdivisions are ordered from most general (largest)
43 | * to most specific (smallest). If the response did not contain any
44 | * subdivisions, this is an empty list.
45 | * @param traits Record for the traits of the requested IP address.
46 | * @see GeoIP2 Web
47 | * Services
48 | */
49 | public record InsightsResponse(
50 | @JsonProperty("anonymizer")
51 | Anonymizer anonymizer,
52 |
53 | @JsonProperty("city")
54 | City city,
55 |
56 | @JsonProperty("continent")
57 | Continent continent,
58 |
59 | @JsonProperty("country")
60 | Country country,
61 |
62 | @JsonProperty("location")
63 | Location location,
64 |
65 | @JsonProperty("maxmind")
66 | MaxMind maxmind,
67 |
68 | @JsonProperty("postal")
69 | Postal postal,
70 |
71 | @JsonProperty("registered_country")
72 | Country registeredCountry,
73 |
74 | @JsonProperty("represented_country")
75 | RepresentedCountry representedCountry,
76 |
77 | @JsonProperty("subdivisions")
78 | List subdivisions,
79 |
80 | @JsonProperty("traits")
81 | Traits traits
82 | ) implements JsonSerializable {
83 |
84 | /**
85 | * Compact canonical constructor that sets defaults for null values.
86 | */
87 | public InsightsResponse {
88 | anonymizer = anonymizer != null ? anonymizer : new Anonymizer();
89 | city = city != null ? city : new City();
90 | continent = continent != null ? continent : new Continent();
91 | country = country != null ? country : new Country();
92 | location = location != null ? location : new Location();
93 | maxmind = maxmind != null ? maxmind : new MaxMind();
94 | postal = postal != null ? postal : new Postal();
95 | registeredCountry = registeredCountry != null ? registeredCountry : new Country();
96 | representedCountry = representedCountry != null
97 | ? representedCountry : new RepresentedCountry();
98 | subdivisions = subdivisions != null ? List.copyOf(subdivisions) : List.of();
99 | traits = traits != null ? traits : new Traits();
100 | }
101 |
102 | /**
103 | * @return City record for the requested IP address.
104 | * @deprecated Use {@link #city()} instead. This method will be removed in 6.0.0.
105 | */
106 | @Deprecated(since = "5.0.0", forRemoval = true)
107 | public City getCity() {
108 | return city();
109 | }
110 |
111 | /**
112 | * @return Continent record for the requested IP address.
113 | * @deprecated Use {@link #continent()} instead. This method will be removed in 6.0.0.
114 | */
115 | @Deprecated(since = "5.0.0", forRemoval = true)
116 | public Continent getContinent() {
117 | return continent();
118 | }
119 |
120 | /**
121 | * @return Country record for the requested IP address. This object
122 | * represents the country where MaxMind believes the end user is
123 | * located.
124 | * @deprecated Use {@link #country()} instead. This method will be removed in 6.0.0.
125 | */
126 | @Deprecated(since = "5.0.0", forRemoval = true)
127 | public Country getCountry() {
128 | return country();
129 | }
130 |
131 | /**
132 | * @return Location record for the requested IP address.
133 | * @deprecated Use {@link #location()} instead. This method will be removed in 6.0.0.
134 | */
135 | @Deprecated(since = "5.0.0", forRemoval = true)
136 | public Location getLocation() {
137 | return location();
138 | }
139 |
140 | /**
141 | * @return MaxMind record containing data related to your account.
142 | * @deprecated Use {@link #maxmind()} instead. This method will be removed in 6.0.0.
143 | */
144 | @Deprecated(since = "5.0.0", forRemoval = true)
145 | @JsonProperty("maxmind")
146 | public MaxMind getMaxMind() {
147 | return maxmind();
148 | }
149 |
150 | /**
151 | * @return the postal
152 | * @deprecated Use {@link #postal()} instead. This method will be removed in 6.0.0.
153 | */
154 | @Deprecated(since = "5.0.0", forRemoval = true)
155 | public Postal getPostal() {
156 | return postal();
157 | }
158 |
159 | /**
160 | * @return Registered country record for the requested IP address. This
161 | * record represents the country where the ISP has registered a
162 | * given IP block and may differ from the user's country.
163 | * @deprecated Use {@link #registeredCountry()} instead. This method will be removed in 6.0.0.
164 | */
165 | @Deprecated(since = "5.0.0", forRemoval = true)
166 | @JsonProperty("registered_country")
167 | public Country getRegisteredCountry() {
168 | return registeredCountry();
169 | }
170 |
171 | /**
172 | * @return Represented country record for the requested IP address. The
173 | * represented country is used for things like military bases. It is
174 | * only present when the represented country differs from the
175 | * country.
176 | * @deprecated Use {@link #representedCountry()} instead. This method will be removed in 6.0.0.
177 | */
178 | @Deprecated(since = "5.0.0", forRemoval = true)
179 | @JsonProperty("represented_country")
180 | public RepresentedCountry getRepresentedCountry() {
181 | return representedCountry();
182 | }
183 |
184 | /**
185 | * @return An {@link List} of {@link Subdivision} objects representing the
186 | * country subdivisions for the requested IP address. The number and
187 | * type of subdivisions varies by country, but a subdivision is
188 | * typically a state, province, county, etc. Subdivisions are
189 | * ordered from most general (largest) to most specific (smallest).
190 | * If the response did not contain any subdivisions, this method
191 | * returns an empty array.
192 | * @deprecated Use {@link #subdivisions()} instead. This method will be removed in 6.0.0.
193 | */
194 | @Deprecated(since = "5.0.0", forRemoval = true)
195 | public List getSubdivisions() {
196 | return new ArrayList<>(subdivisions());
197 | }
198 |
199 | /**
200 | * @return Record for the traits of the requested IP address.
201 | * @deprecated Use {@link #traits()} instead. This method will be removed in 6.0.0.
202 | */
203 | @Deprecated(since = "5.0.0", forRemoval = true)
204 | public Traits getTraits() {
205 | return traits();
206 | }
207 |
208 | /**
209 | * @return An object representing the most specific subdivision returned. If
210 | * the response did not contain any subdivisions, this method
211 | * returns an empty {@link Subdivision} object.
212 | */
213 | @JsonIgnore
214 | public Subdivision mostSpecificSubdivision() {
215 | if (subdivisions().isEmpty()) {
216 | return new Subdivision();
217 | }
218 | return subdivisions().get(subdivisions().size() - 1);
219 | }
220 |
221 | /**
222 | * @return An object representing the most specific subdivision returned. If
223 | * the response did not contain any subdivisions, this method
224 | * returns an empty {@link Subdivision} object.
225 | * @deprecated Use {@link #mostSpecificSubdivision()} instead. This method will be removed
226 | * in 6.0.0.
227 | */
228 | @JsonIgnore
229 | @Deprecated(since = "5.0.0", forRemoval = true)
230 | public Subdivision getMostSpecificSubdivision() {
231 | return mostSpecificSubdivision();
232 | }
233 |
234 | /**
235 | * @return An object representing the least specific subdivision returned. If
236 | * the response did not contain any subdivisions, this method
237 | * returns an empty {@link Subdivision} object.
238 | */
239 | @JsonIgnore
240 | public Subdivision leastSpecificSubdivision() {
241 | if (subdivisions().isEmpty()) {
242 | return new Subdivision();
243 | }
244 | return subdivisions().get(0);
245 | }
246 |
247 | /**
248 | * @return An object representing the least specific subdivision returned. If
249 | * the response did not contain any subdivisions, this method
250 | * returns an empty {@link Subdivision} object.
251 | * @deprecated Use {@link #leastSpecificSubdivision()} instead. This method will be removed
252 | * in 6.0.0.
253 | */
254 | @JsonIgnore
255 | @Deprecated(since = "5.0.0", forRemoval = true)
256 | public Subdivision getLeastSpecificSubdivision() {
257 | return leastSpecificSubdivision();
258 | }
259 | }
260 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | https://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | https://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/model/EnterpriseResponse.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnore;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.maxmind.db.MaxMindDbParameter;
6 | import com.maxmind.geoip2.JsonSerializable;
7 | import com.maxmind.geoip2.record.City;
8 | import com.maxmind.geoip2.record.Continent;
9 | import com.maxmind.geoip2.record.Country;
10 | import com.maxmind.geoip2.record.Location;
11 | import com.maxmind.geoip2.record.MaxMind;
12 | import com.maxmind.geoip2.record.Postal;
13 | import com.maxmind.geoip2.record.RepresentedCountry;
14 | import com.maxmind.geoip2.record.Subdivision;
15 | import com.maxmind.geoip2.record.Traits;
16 | import java.util.ArrayList;
17 | import java.util.List;
18 |
19 | /**
20 | *
21 | * This class provides a model for the data returned by the GeoIP2 Enterprise
22 | * database
23 | *
24 | *
25 | * @param city City record for the requested IP address.
26 | * @param continent Continent record for the requested IP address.
27 | * @param country Country record for the requested IP address. This object represents the country
28 | * where MaxMind believes the end user is located.
29 | * @param location Location record for the requested IP address.
30 | * @param maxmind MaxMind record containing data related to your account.
31 | * @param postal Postal record for the requested IP address.
32 | * @param registeredCountry Registered country record for the requested IP address. This record
33 | * represents the country where the ISP has registered a given IP block
34 | * and may differ from the user's country.
35 | * @param representedCountry Represented country record for the requested IP address. The
36 | * represented country is used for things like military bases. It is
37 | * only present when the represented country differs from the country.
38 | * @param subdivisions An {@link List} of {@link Subdivision} objects representing the country
39 | * subdivisions for the requested IP address. The number and type of
40 | * subdivisions varies by country, but a subdivision is typically a state,
41 | * province, county, etc. Subdivisions are ordered from most general (largest)
42 | * to most specific (smallest). If the response did not contain any
43 | * subdivisions, this is an empty list.
44 | * @param traits Record for the traits of the requested IP address.
45 | */
46 | public record EnterpriseResponse(
47 | @JsonProperty("city")
48 | @MaxMindDbParameter(name = "city")
49 | City city,
50 |
51 | @JsonProperty("continent")
52 | @MaxMindDbParameter(name = "continent")
53 | Continent continent,
54 |
55 | @JsonProperty("country")
56 | @MaxMindDbParameter(name = "country")
57 | Country country,
58 |
59 | @JsonProperty("location")
60 | @MaxMindDbParameter(name = "location")
61 | Location location,
62 |
63 | @JsonProperty("maxmind")
64 | @MaxMindDbParameter(name = "maxmind")
65 | MaxMind maxmind,
66 |
67 | @JsonProperty("postal")
68 | @MaxMindDbParameter(name = "postal")
69 | Postal postal,
70 |
71 | @JsonProperty("registered_country")
72 | @MaxMindDbParameter(name = "registered_country")
73 | Country registeredCountry,
74 |
75 | @JsonProperty("represented_country")
76 | @MaxMindDbParameter(name = "represented_country")
77 | RepresentedCountry representedCountry,
78 |
79 | @JsonProperty("subdivisions")
80 | @MaxMindDbParameter(name = "subdivisions")
81 | List subdivisions,
82 |
83 | @JsonProperty("traits")
84 | @MaxMindDbParameter(name = "traits")
85 | Traits traits
86 | ) implements JsonSerializable {
87 |
88 | /**
89 | * Compact canonical constructor that sets defaults for null values.
90 | */
91 | public EnterpriseResponse {
92 | city = city != null ? city : new City();
93 | continent = continent != null ? continent : new Continent();
94 | country = country != null ? country : new Country();
95 | location = location != null ? location : new Location();
96 | maxmind = maxmind != null ? maxmind : new MaxMind();
97 | postal = postal != null ? postal : new Postal();
98 | registeredCountry = registeredCountry != null ? registeredCountry : new Country();
99 | representedCountry = representedCountry != null
100 | ? representedCountry : new RepresentedCountry();
101 | subdivisions = subdivisions != null ? List.copyOf(subdivisions) : List.of();
102 | traits = traits != null ? traits : new Traits();
103 | }
104 |
105 | /**
106 | * Constructs an instance of {@code EnterpriseResponse} with only required parameters.
107 | *
108 | * @param response the response
109 | * @param locales the locales
110 | */
111 | public EnterpriseResponse(
112 | EnterpriseResponse response,
113 | List locales
114 | ) {
115 | this(
116 | new City(response.city(), locales),
117 | new Continent(response.continent(), locales),
118 | new Country(response.country(), locales),
119 | response.location(),
120 | response.maxmind(),
121 | response.postal(),
122 | new Country(response.registeredCountry(), locales),
123 | new RepresentedCountry(response.representedCountry(), locales),
124 | mapSubdivisions(response.subdivisions(), locales),
125 | response.traits()
126 | );
127 | }
128 |
129 | private static ArrayList mapSubdivisions(
130 | List subdivisions,
131 | List locales
132 | ) {
133 | var subdivisions2 = new ArrayList(subdivisions.size());
134 | for (var subdivision : subdivisions) {
135 | subdivisions2.add(new Subdivision(subdivision, locales));
136 | }
137 | return subdivisions2;
138 | }
139 |
140 | /**
141 | * @return City record for the requested IP address.
142 | * @deprecated Use {@link #city()} instead. This method will be removed in 6.0.0.
143 | */
144 | @Deprecated(since = "5.0.0", forRemoval = true)
145 | public City getCity() {
146 | return city();
147 | }
148 |
149 | /**
150 | * @return Continent record for the requested IP address.
151 | * @deprecated Use {@link #continent()} instead. This method will be removed in 6.0.0.
152 | */
153 | @Deprecated(since = "5.0.0", forRemoval = true)
154 | public Continent getContinent() {
155 | return continent();
156 | }
157 |
158 | /**
159 | * @return Country record for the requested IP address. This object
160 | * represents the country where MaxMind believes the end user is
161 | * located.
162 | * @deprecated Use {@link #country()} instead. This method will be removed in 6.0.0.
163 | */
164 | @Deprecated(since = "5.0.0", forRemoval = true)
165 | public Country getCountry() {
166 | return country();
167 | }
168 |
169 | /**
170 | * @return Location record for the requested IP address.
171 | * @deprecated Use {@link #location()} instead. This method will be removed in 6.0.0.
172 | */
173 | @Deprecated(since = "5.0.0", forRemoval = true)
174 | public Location getLocation() {
175 | return location();
176 | }
177 |
178 | /**
179 | * @return MaxMind record containing data related to your account.
180 | * @deprecated Use {@link #maxmind()} instead. This method will be removed in 6.0.0.
181 | */
182 | @Deprecated(since = "5.0.0", forRemoval = true)
183 | @JsonProperty("maxmind")
184 | public MaxMind getMaxMind() {
185 | return maxmind();
186 | }
187 |
188 | /**
189 | * @return the postal
190 | * @deprecated Use {@link #postal()} instead. This method will be removed in 6.0.0.
191 | */
192 | @Deprecated(since = "5.0.0", forRemoval = true)
193 | public Postal getPostal() {
194 | return postal();
195 | }
196 |
197 | /**
198 | * @return Registered country record for the requested IP address. This
199 | * record represents the country where the ISP has registered a
200 | * given IP block and may differ from the user's country.
201 | * @deprecated Use {@link #registeredCountry()} instead. This method will be removed in 6.0.0.
202 | */
203 | @Deprecated(since = "5.0.0", forRemoval = true)
204 | @JsonProperty("registered_country")
205 | public Country getRegisteredCountry() {
206 | return registeredCountry();
207 | }
208 |
209 | /**
210 | * @return Represented country record for the requested IP address. The
211 | * represented country is used for things like military bases. It is
212 | * only present when the represented country differs from the
213 | * country.
214 | * @deprecated Use {@link #representedCountry()} instead. This method will be removed in 6.0.0.
215 | */
216 | @Deprecated(since = "5.0.0", forRemoval = true)
217 | @JsonProperty("represented_country")
218 | public RepresentedCountry getRepresentedCountry() {
219 | return representedCountry();
220 | }
221 |
222 | /**
223 | * @return An {@link List} of {@link Subdivision} objects representing the
224 | * country subdivisions for the requested IP address. The number and
225 | * type of subdivisions varies by country, but a subdivision is
226 | * typically a state, province, county, etc. Subdivisions are
227 | * ordered from most general (largest) to most specific (smallest).
228 | * If the response did not contain any subdivisions, this method
229 | * returns an empty array.
230 | * @deprecated Use {@link #subdivisions()} instead. This method will be removed in 6.0.0.
231 | */
232 | @Deprecated(since = "5.0.0", forRemoval = true)
233 | public List getSubdivisions() {
234 | return new ArrayList<>(subdivisions());
235 | }
236 |
237 | /**
238 | * @return Record for the traits of the requested IP address.
239 | * @deprecated Use {@link #traits()} instead. This method will be removed in 6.0.0.
240 | */
241 | @Deprecated(since = "5.0.0", forRemoval = true)
242 | public Traits getTraits() {
243 | return traits();
244 | }
245 |
246 | /**
247 | * @return An object representing the most specific subdivision returned. If
248 | * the response did not contain any subdivisions, this method
249 | * returns an empty {@link Subdivision} object.
250 | */
251 | @JsonIgnore
252 | public Subdivision mostSpecificSubdivision() {
253 | if (subdivisions().isEmpty()) {
254 | return new Subdivision();
255 | }
256 | return subdivisions().get(subdivisions().size() - 1);
257 | }
258 |
259 | /**
260 | * @return An object representing the most specific subdivision returned. If
261 | * the response did not contain any subdivisions, this method
262 | * returns an empty {@link Subdivision} object.
263 | * @deprecated Use {@link #mostSpecificSubdivision()} instead. This method will be removed
264 | * in 6.0.0.
265 | */
266 | @JsonIgnore
267 | @Deprecated(since = "5.0.0", forRemoval = true)
268 | public Subdivision getMostSpecificSubdivision() {
269 | return mostSpecificSubdivision();
270 | }
271 |
272 | /**
273 | * @return An object representing the least specific subdivision returned. If
274 | * the response did not contain any subdivisions, this method
275 | * returns an empty {@link Subdivision} object.
276 | */
277 | @JsonIgnore
278 | public Subdivision leastSpecificSubdivision() {
279 | if (subdivisions().isEmpty()) {
280 | return new Subdivision();
281 | }
282 | return subdivisions().get(0);
283 | }
284 |
285 | /**
286 | * @return An object representing the least specific subdivision returned. If
287 | * the response did not contain any subdivisions, this method
288 | * returns an empty {@link Subdivision} object.
289 | * @deprecated Use {@link #leastSpecificSubdivision()} instead. This method will be removed
290 | * in 6.0.0.
291 | */
292 | @JsonIgnore
293 | @Deprecated(since = "5.0.0", forRemoval = true)
294 | public Subdivision getLeastSpecificSubdivision() {
295 | return leastSpecificSubdivision();
296 | }
297 | }
298 |
--------------------------------------------------------------------------------
/src/test/java/com/maxmind/geoip2/model/InsightsResponseTest.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.model;
2 |
3 | import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
4 | import static com.github.tomakehurst.wiremock.client.WireMock.get;
5 | import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
6 | import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
7 | import static com.maxmind.geoip2.json.File.readJsonFile;
8 | import static org.junit.jupiter.api.Assertions.assertEquals;
9 | import static org.junit.jupiter.api.Assertions.assertNotNull;
10 | import static org.junit.jupiter.api.Assertions.assertTrue;
11 | import static org.junit.jupiter.api.Assertions.fail;
12 |
13 | import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
14 | import com.github.tomakehurst.wiremock.junit5.WireMockTest;
15 | import com.maxmind.geoip2.WebServiceClient;
16 | import com.maxmind.geoip2.exception.GeoIp2Exception;
17 | import com.maxmind.geoip2.model.ConnectionTypeResponse.ConnectionType;
18 | import com.maxmind.geoip2.record.Anonymizer;
19 | import com.maxmind.geoip2.record.Location;
20 | import com.maxmind.geoip2.record.MaxMind;
21 | import com.maxmind.geoip2.record.Postal;
22 | import com.maxmind.geoip2.record.Subdivision;
23 | import com.maxmind.geoip2.record.Traits;
24 | import java.io.IOException;
25 | import java.net.InetAddress;
26 | import java.net.URISyntaxException;
27 | import java.time.LocalDate;
28 | import java.util.List;
29 | import org.junit.jupiter.api.BeforeEach;
30 | import org.junit.jupiter.api.Test;
31 | import org.junit.jupiter.api.extension.RegisterExtension;
32 |
33 | @WireMockTest
34 | public class InsightsResponseTest {
35 | @RegisterExtension
36 | static WireMockExtension wireMock = WireMockExtension.newInstance()
37 | .options(wireMockConfig().dynamicPort().dynamicHttpsPort())
38 | .build();
39 |
40 | private InsightsResponse insights;
41 |
42 | @BeforeEach
43 | public void createClient() throws IOException, GeoIp2Exception,
44 | URISyntaxException {
45 | wireMock.stubFor(get(urlEqualTo("/geoip/v2.1/insights/1.1.1.1"))
46 | .willReturn(aResponse()
47 | .withStatus(200)
48 | .withHeader("Content-Type",
49 | "application/vnd.maxmind.com-insights+json; charset=UTF-8; version=2.1")
50 | .withBody(readJsonFile("insights0"))));
51 | wireMock.stubFor(get(urlEqualTo("/geoip/v2.1/insights/1.1.1.2"))
52 | .willReturn(aResponse()
53 | .withStatus(200)
54 | .withHeader("Content-Type",
55 | "application/vnd.maxmind.com-insights+json; charset=UTF-8; version=2.1")
56 | .withBody(readJsonFile("insights1"))));
57 |
58 | WebServiceClient client = new WebServiceClient.Builder(6, "0123456789")
59 | .host("localhost")
60 | .port(wireMock.getPort())
61 | .disableHttps()
62 | .build();
63 |
64 | this.insights = client.insights(InetAddress.getByName("1.1.1.1"));
65 | }
66 |
67 | @Test
68 | public void testSubdivisionsList() {
69 | List subdivisionsList = this.insights.subdivisions();
70 | assertNotNull(subdivisionsList, "city.getSubdivisionsList returns null");
71 | if (subdivisionsList.isEmpty()) {
72 | fail("subdivisionsList is empty");
73 | }
74 | Subdivision subdivision = subdivisionsList.get(0);
75 | assertEquals(
76 | Integer.valueOf(88),
77 | subdivision.confidence(),
78 | "subdivision.confidence() does not return 88"
79 | );
80 | assertEquals(
81 | 574635,
82 | subdivision.geonameId().intValue(),
83 | "subdivision.geonameId() does not return 574635"
84 | );
85 | assertEquals(
86 | "MN",
87 | subdivision.isoCode(),
88 | "subdivision.code() does not return MN"
89 | );
90 | }
91 |
92 | @Test
93 | public void mostSpecificSubdivision() {
94 | assertEquals(
95 | "TT",
96 | this.insights.mostSpecificSubdivision().isoCode(),
97 | "Most specific subdivision returns last subdivision"
98 | );
99 | }
100 |
101 | @Test
102 | public void leastSpecificSubdivision() {
103 | assertEquals(
104 | "MN",
105 | this.insights.leastSpecificSubdivision().isoCode(),
106 | "Most specific subdivision returns first subdivision"
107 | );
108 | }
109 |
110 | @Test
111 | public void testTraits() {
112 | Traits traits = this.insights.traits();
113 |
114 | assertNotNull(traits, "city.traits() returns null");
115 | assertEquals(
116 | Long.valueOf(1234),
117 | traits.autonomousSystemNumber(),
118 | "traits.autonomousSystemNumber() does not return 1234"
119 | );
120 | assertEquals(
121 |
122 | "AS Organization",
123 | traits.autonomousSystemOrganization(),
124 | "traits.autonomousSystemOrganization() does not return AS Organization"
125 | );
126 | assertEquals(
127 |
128 | ConnectionType.CABLE_DSL,
129 | traits.connectionType(),
130 | "traits.connectionType() does not return Cable/DSL"
131 | );
132 | assertEquals(
133 | "example.com",
134 | traits.domain(),
135 | "traits.domain() does not return example.com"
136 | );
137 | assertEquals(
138 | "1.2.3.4",
139 | traits.ipAddress().getHostAddress(),
140 | "traits.ipAddress() does not return 1.2.3.4"
141 | );
142 | assertTrue(traits.isAnonymous(), "traits.isAnonymous() returns true");
143 | assertTrue(traits.isAnonymousVpn(), "traits.isAnonymousVpn() returns true");
144 | assertTrue(traits.isHostingProvider(), "traits.isHostingProvider() returns true");
145 | assertTrue(traits.isPublicProxy(), "traits.isPublicProxy() returns true");
146 | assertTrue(traits.isResidentialProxy(), "traits.isResidentialProxy() returns true");
147 | assertTrue(traits.isTorExitNode(), "traits.isTorExitNode() returns true");
148 | assertEquals(
149 | "Comcast",
150 | traits.isp(),
151 | "traits.isp() does not return Comcast"
152 | );
153 | assertEquals(
154 | "Blorg",
155 | traits.organization(),
156 | "traits.organization() does not return Blorg"
157 | );
158 | assertEquals(
159 | "college",
160 | traits.userType(),
161 | "traits.userType() does not return userType"
162 | );
163 | assertEquals(
164 | Double.valueOf(1.3),
165 | traits.staticIpScore(),
166 | "traits.staticIpScore() does not return 1.3"
167 | );
168 | assertEquals(
169 | Integer.valueOf(2),
170 | traits.userCount(),
171 | "traits.userCount() does not return 2"
172 | );
173 | assertEquals(
174 | Double.valueOf(0.01),
175 | traits.ipRiskSnapshot(),
176 | "traits.ipRiskSnapshot() does not return 0.01"
177 | );
178 | }
179 |
180 | @Test
181 | public void testAnonymizer() {
182 | Anonymizer anonymizer = this.insights.anonymizer();
183 |
184 | assertNotNull(anonymizer, "insights.anonymizer() returns null");
185 | assertEquals(
186 | Integer.valueOf(99),
187 | anonymizer.confidence(),
188 | "anonymizer.confidence() does not return 99"
189 | );
190 | assertTrue(anonymizer.isAnonymous(), "anonymizer.isAnonymous() returns true");
191 | assertTrue(anonymizer.isAnonymousVpn(), "anonymizer.isAnonymousVpn() returns true");
192 | assertTrue(anonymizer.isHostingProvider(), "anonymizer.isHostingProvider() returns true");
193 | assertTrue(anonymizer.isPublicProxy(), "anonymizer.isPublicProxy() returns true");
194 | assertTrue(
195 | anonymizer.isResidentialProxy(),
196 | "anonymizer.isResidentialProxy() returns true"
197 | );
198 | assertTrue(anonymizer.isTorExitNode(), "anonymizer.isTorExitNode() returns true");
199 | assertEquals(
200 | LocalDate.parse("2024-12-31"),
201 | anonymizer.networkLastSeen(),
202 | "anonymizer.networkLastSeen() does not return 2024-12-31"
203 | );
204 | assertEquals(
205 | "NordVPN",
206 | anonymizer.providerName(),
207 | "anonymizer.providerName() does not return NordVPN"
208 | );
209 | }
210 |
211 | @Test
212 | public void testLocation() {
213 |
214 | Location location = this.insights.location();
215 |
216 | assertNotNull(location, "city.location() returns null");
217 |
218 | assertEquals(
219 | Integer.valueOf(24626),
220 | location.averageIncome(),
221 | "location.averageIncome() does not return 24626"
222 | );
223 |
224 | assertEquals(
225 | Integer.valueOf(1500),
226 | location.accuracyRadius(),
227 | "location.accuracyRadius() does not return 1500"
228 | );
229 |
230 | double latitude = location.latitude();
231 | assertEquals(
232 | 44.98,
233 | latitude,
234 | 0.1,
235 | "location.latitude() does not return 44.98"
236 | );
237 | double longitude = location.longitude();
238 | assertEquals(
239 | 93.2636,
240 | longitude,
241 | 0.1,
242 | "location.longitude() does not return 93.2636"
243 | );
244 | assertEquals(
245 | Integer.valueOf(1341),
246 | location.populationDensity(),
247 | "location.populationDensity() does not return 1341"
248 | );
249 | assertEquals(
250 | "America/Chicago",
251 | location.timeZone(),
252 | "location.timeZone() does not return America/Chicago"
253 | );
254 | }
255 |
256 | @Test
257 | public void testMaxMind() {
258 | MaxMind maxmind = this.insights.maxmind();
259 | assertEquals(
260 | 11, maxmind
261 | .queriesRemaining().intValue(),
262 | "Correct number of queries remaining"
263 | );
264 | }
265 |
266 | @Test
267 | public void testPostal() {
268 |
269 | Postal postal = this.insights.postal();
270 | assertEquals(
271 | "55401",
272 | postal.code(),
273 | "postal.code() does not return 55401"
274 | );
275 | assertEquals(
276 | Integer.valueOf(33),
277 | postal.confidence(),
278 | "postal.confidence() does not return 33"
279 | );
280 | }
281 |
282 | @Test
283 | public void testRepresentedCountry() {
284 | assertNotNull(
285 | this.insights.representedCountry(),
286 | "city.representedCountry() returns null"
287 | );
288 |
289 | assertEquals(
290 | "C",
291 | this.insights.representedCountry().type(),
292 | "city.representedCountry().type() does not return C"
293 | );
294 | assertTrue(
295 | this.insights.representedCountry().isInEuropeanUnion(),
296 | "city.representedCountry().isInEuropeanUnion() does not return true"
297 | );
298 | }
299 |
300 | @Test
301 | public void testIsInEuropeanUnion() throws IOException, GeoIp2Exception {
302 | // This uses an alternate fixture where we have the
303 | // is_in_european_union flag set in locations not set in the other
304 | // fixture.
305 | WebServiceClient client = new WebServiceClient.Builder(6, "0123456789")
306 | .host("localhost")
307 | .port(wireMock.getPort())
308 | .disableHttps()
309 | .build();
310 |
311 | InsightsResponse insights = client.insights(
312 | InetAddress.getByName("1.1.1.2"));
313 |
314 | assertTrue(
315 | insights.country().isInEuropeanUnion(),
316 | "getCountry().isInEuropeanUnion() does not return true"
317 | );
318 | assertTrue(
319 | insights.registeredCountry().isInEuropeanUnion(),
320 | "getRegisteredCountry().() isInEuropeanUnion = does not return true"
321 | );
322 | }
323 | }
324 |
--------------------------------------------------------------------------------
/src/main/java/com/maxmind/geoip2/model/CityResponse.java:
--------------------------------------------------------------------------------
1 | package com.maxmind.geoip2.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnore;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.maxmind.db.MaxMindDbParameter;
6 | import com.maxmind.geoip2.JsonSerializable;
7 | import com.maxmind.geoip2.record.City;
8 | import com.maxmind.geoip2.record.Continent;
9 | import com.maxmind.geoip2.record.Country;
10 | import com.maxmind.geoip2.record.Location;
11 | import com.maxmind.geoip2.record.MaxMind;
12 | import com.maxmind.geoip2.record.Postal;
13 | import com.maxmind.geoip2.record.RepresentedCountry;
14 | import com.maxmind.geoip2.record.Subdivision;
15 | import com.maxmind.geoip2.record.Traits;
16 | import java.util.ArrayList;
17 | import java.util.List;
18 |
19 | /**
20 | * This class provides a model for the data returned by the City Plus web
21 | * service and the City database.
22 | *
23 | * @param city City record for the requested IP address.
24 | * @param continent Continent record for the requested IP address.
25 | * @param country Country record for the requested IP address. This object represents the country
26 | * where MaxMind believes the end user is located.
27 | * @param location Location record for the requested IP address.
28 | * @param maxmind MaxMind record containing data related to your account.
29 | * @param postal Postal record for the requested IP address.
30 | * @param registeredCountry Registered country record for the requested IP address. This record
31 | * represents the country where the ISP has registered a given IP block
32 | * and may differ from the user's country.
33 | * @param representedCountry Represented country record for the requested IP address. The
34 | * represented country is used for things like military bases. It is
35 | * only present when the represented country differs from the country.
36 | * @param subdivisions An {@link List} of {@link Subdivision} objects representing the country
37 | * subdivisions for the requested IP address. The number and type of
38 | * subdivisions varies by country, but a subdivision is typically a state,
39 | * province, county, etc. Subdivisions are ordered from most general (largest)
40 | * to most specific (smallest). If the response did not contain any
41 | * subdivisions, this is an empty list.
42 | * @param traits Record for the traits of the requested IP address.
43 | * @see GeoIP2 Web
44 | * Services
45 | */
46 | public record CityResponse(
47 | @JsonProperty("city")
48 | @MaxMindDbParameter(name = "city")
49 | City city,
50 |
51 | @JsonProperty("continent")
52 | @MaxMindDbParameter(name = "continent")
53 | Continent continent,
54 |
55 | @JsonProperty("country")
56 | @MaxMindDbParameter(name = "country")
57 | Country country,
58 |
59 | @JsonProperty("location")
60 | @MaxMindDbParameter(name = "location")
61 | Location location,
62 |
63 | @JsonProperty("maxmind")
64 | @MaxMindDbParameter(name = "maxmind")
65 | MaxMind maxmind,
66 |
67 | @JsonProperty("postal")
68 | @MaxMindDbParameter(name = "postal")
69 | Postal postal,
70 |
71 | @JsonProperty("registered_country")
72 | @MaxMindDbParameter(name = "registered_country")
73 | Country registeredCountry,
74 |
75 | @JsonProperty("represented_country")
76 | @MaxMindDbParameter(name = "represented_country")
77 | RepresentedCountry representedCountry,
78 |
79 | @JsonProperty("subdivisions")
80 | @MaxMindDbParameter(name = "subdivisions")
81 | List subdivisions,
82 |
83 | @JsonProperty("traits")
84 | @MaxMindDbParameter(name = "traits")
85 | Traits traits
86 | ) implements JsonSerializable {
87 |
88 | /**
89 | * Compact canonical constructor that sets defaults for null values.
90 | */
91 | public CityResponse {
92 | city = city != null ? city : new City();
93 | continent = continent != null ? continent : new Continent();
94 | country = country != null ? country : new Country();
95 | location = location != null ? location : new Location();
96 | maxmind = maxmind != null ? maxmind : new MaxMind();
97 | postal = postal != null ? postal : new Postal();
98 | registeredCountry = registeredCountry != null ? registeredCountry : new Country();
99 | representedCountry = representedCountry != null
100 | ? representedCountry : new RepresentedCountry();
101 | subdivisions = subdivisions != null ? List.copyOf(subdivisions) : List.of();
102 | traits = traits != null ? traits : new Traits();
103 | }
104 |
105 | /**
106 | * Constructs an instance of {@code CityResponse} with the specified parameters.
107 | *
108 | * @param response the response
109 | * @param locales the locales
110 | */
111 | public CityResponse(
112 | CityResponse response,
113 | List locales
114 | ) {
115 | this(
116 | new City(response.city(), locales),
117 | new Continent(response.continent(), locales),
118 | new Country(response.country(), locales),
119 | response.location(),
120 | response.maxmind(),
121 | response.postal(),
122 | new Country(response.registeredCountry(), locales),
123 | new RepresentedCountry(response.representedCountry(), locales),
124 | mapSubdivisions(response.subdivisions(), locales),
125 | response.traits()
126 | );
127 | }
128 |
129 | private static ArrayList mapSubdivisions(
130 | List subdivisions,
131 | List locales
132 | ) {
133 | var subdivisions2 = new ArrayList(subdivisions.size());
134 | for (var subdivision : subdivisions) {
135 | subdivisions2.add(new Subdivision(subdivision, locales));
136 | }
137 | return subdivisions2;
138 | }
139 |
140 | /**
141 | * @return City record for the requested IP address.
142 | * @deprecated Use {@link #city()} instead. This method will be removed in 6.0.0.
143 | */
144 | @Deprecated(since = "5.0.0", forRemoval = true)
145 | public City getCity() {
146 | return city();
147 | }
148 |
149 | /**
150 | * @return Continent record for the requested IP address.
151 | * @deprecated Use {@link #continent()} instead. This method will be removed in 6.0.0.
152 | */
153 | @Deprecated(since = "5.0.0", forRemoval = true)
154 | public Continent getContinent() {
155 | return continent();
156 | }
157 |
158 | /**
159 | * @return Country record for the requested IP address. This object
160 | * represents the country where MaxMind believes the end user is
161 | * located.
162 | * @deprecated Use {@link #country()} instead. This method will be removed in 6.0.0.
163 | */
164 | @Deprecated(since = "5.0.0", forRemoval = true)
165 | public Country getCountry() {
166 | return country();
167 | }
168 |
169 | /**
170 | * @return Location record for the requested IP address.
171 | * @deprecated Use {@link #location()} instead. This method will be removed in 6.0.0.
172 | */
173 | @Deprecated(since = "5.0.0", forRemoval = true)
174 | public Location getLocation() {
175 | return location();
176 | }
177 |
178 | /**
179 | * @return MaxMind record containing data related to your account.
180 | * @deprecated Use {@link #maxmind()} instead. This method will be removed in 6.0.0.
181 | */
182 | @Deprecated(since = "5.0.0", forRemoval = true)
183 | @JsonProperty("maxmind")
184 | public MaxMind getMaxMind() {
185 | return maxmind();
186 | }
187 |
188 | /**
189 | * @return the postal
190 | * @deprecated Use {@link #postal()} instead. This method will be removed in 6.0.0.
191 | */
192 | @Deprecated(since = "5.0.0", forRemoval = true)
193 | public Postal getPostal() {
194 | return postal();
195 | }
196 |
197 | /**
198 | * @return Registered country record for the requested IP address. This
199 | * record represents the country where the ISP has registered a
200 | * given IP block and may differ from the user's country.
201 | * @deprecated Use {@link #registeredCountry()} instead. This method will be removed in 6.0.0.
202 | */
203 | @Deprecated(since = "5.0.0", forRemoval = true)
204 | @JsonProperty("registered_country")
205 | public Country getRegisteredCountry() {
206 | return registeredCountry();
207 | }
208 |
209 | /**
210 | * @return Represented country record for the requested IP address. The
211 | * represented country is used for things like military bases. It is
212 | * only present when the represented country differs from the
213 | * country.
214 | * @deprecated Use {@link #representedCountry()} instead. This method will be removed in 6.0.0.
215 | */
216 | @Deprecated(since = "5.0.0", forRemoval = true)
217 | @JsonProperty("represented_country")
218 | public RepresentedCountry getRepresentedCountry() {
219 | return representedCountry();
220 | }
221 |
222 | /**
223 | * @return An {@link List} of {@link Subdivision} objects representing the
224 | * country subdivisions for the requested IP address. The number and
225 | * type of subdivisions varies by country, but a subdivision is
226 | * typically a state, province, county, etc. Subdivisions are
227 | * ordered from most general (largest) to most specific (smallest).
228 | * If the response did not contain any subdivisions, this method
229 | * returns an empty array.
230 | * @deprecated Use {@link #subdivisions()} instead. This method will be removed in 6.0.0.
231 | */
232 | @Deprecated(since = "5.0.0", forRemoval = true)
233 | public List getSubdivisions() {
234 | return new ArrayList<>(subdivisions());
235 | }
236 |
237 | /**
238 | * @return Record for the traits of the requested IP address.
239 | * @deprecated Use {@link #traits()} instead. This method will be removed in 6.0.0.
240 | */
241 | @Deprecated(since = "5.0.0", forRemoval = true)
242 | public Traits getTraits() {
243 | return traits();
244 | }
245 |
246 | /**
247 | * @return An object representing the most specific subdivision returned. If
248 | * the response did not contain any subdivisions, this method
249 | * returns an empty {@link Subdivision} object.
250 | */
251 | @JsonIgnore
252 | public Subdivision mostSpecificSubdivision() {
253 | if (subdivisions().isEmpty()) {
254 | return new Subdivision();
255 | }
256 | return subdivisions().get(subdivisions().size() - 1);
257 | }
258 |
259 | /**
260 | * @return An object representing the most specific subdivision returned. If
261 | * the response did not contain any subdivisions, this method
262 | * returns an empty {@link Subdivision} object.
263 | * @deprecated Use {@link #mostSpecificSubdivision()} instead. This method will be removed
264 | * in 6.0.0.
265 | */
266 | @JsonIgnore
267 | @Deprecated(since = "5.0.0", forRemoval = true)
268 | public Subdivision getMostSpecificSubdivision() {
269 | return mostSpecificSubdivision();
270 | }
271 |
272 | /**
273 | * @return An object representing the least specific subdivision returned. If
274 | * the response did not contain any subdivisions, this method
275 | * returns an empty {@link Subdivision} object.
276 | */
277 | @JsonIgnore
278 | public Subdivision leastSpecificSubdivision() {
279 | if (subdivisions().isEmpty()) {
280 | return new Subdivision();
281 | }
282 | return subdivisions().get(0);
283 | }
284 |
285 | /**
286 | * @return An object representing the least specific subdivision returned. If
287 | * the response did not contain any subdivisions, this method
288 | * returns an empty {@link Subdivision} object.
289 | * @deprecated Use {@link #leastSpecificSubdivision()} instead. This method will be removed
290 | * in 6.0.0.
291 | */
292 | @JsonIgnore
293 | @Deprecated(since = "5.0.0", forRemoval = true)
294 | public Subdivision getLeastSpecificSubdivision() {
295 | return leastSpecificSubdivision();
296 | }
297 | }
298 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | com.maxmind.geoip2
5 | geoip2
6 | 5.0.2
7 | jar
8 | MaxMind GeoIP2 API
9 | GeoIP2 webservice client and database reader
10 | https://dev.maxmind.com/geoip?lang=en
11 |
12 |
13 | Apache License, Version 2.0
14 | https://www.apache.org/licenses/LICENSE-2.0.html
15 | repo
16 |
17 |
18 |
19 | MaxMind, Inc.
20 | https://www.maxmind.com/
21 |
22 |
23 | https://github.com/maxmind/GeoIP2-java
24 | scm:git:git://github.com:maxmind/GeoIP2-java.git
25 | scm:git:git@github.com:maxmind/GeoIP2-java.git
26 | HEAD
27 |
28 |
29 | https://github.com/maxmind/GeoIP2-java/issues
30 | GitHub
31 |
32 |
33 |
34 | oschwald
35 | Gregory J. Oschwald
36 | goschwald@maxmind.com
37 |
38 |
39 |
40 |
41 | Central Portal Snapshots
42 | central-portal-snapshots
43 | https://central.sonatype.com/repository/maven-snapshots/
44 |
45 | false
46 |
47 |
48 | true
49 |
50 |
51 |
52 |
53 |
54 | com.maxmind.db
55 | maxmind-db
56 | 4.0.2
57 |
58 |
59 | com.fasterxml.jackson.core
60 | jackson-databind
61 | 2.20.1
62 |
63 |
64 | com.fasterxml.jackson.datatype
65 | jackson-datatype-jsr310
66 | 2.20.1
67 |
68 |
69 | com.fasterxml.jackson.core
70 | jackson-core
71 | 2.20.1
72 |
73 |
74 | com.fasterxml.jackson.core
75 | jackson-annotations
76 | 2.20
77 |
78 |
79 | org.wiremock
80 | wiremock
81 | 3.13.2
82 | test
83 |
84 |
85 | com.fasterxml.jackson.jr
86 | jackson-jr-objects
87 | 2.20.1
88 | test
89 |
90 |
91 | com.jcabi
92 | jcabi-matchers
93 | 1.8.0
94 | test
95 |
96 |
97 | org.junit.jupiter
98 | junit-jupiter
99 | 6.0.1
100 | test
101 |
102 |
103 |
104 | UTF-8
105 |
106 |
107 |
108 |
109 | org.apache.maven.plugins
110 | maven-enforcer-plugin
111 | 3.6.2
112 |
113 |
114 | enforce-maven
115 |
116 | enforce
117 |
118 |
119 |
120 |
121 | 3.6.3
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | org.apache.maven.plugins
130 | maven-checkstyle-plugin
131 | 3.6.0
132 |
133 | true
134 | checkstyle.xml
135 | checkstyle-suppressions.xml
136 | warning
137 |
138 |
139 |
140 | com.puppycrawl.tools
141 | checkstyle
142 | 12.2.0
143 |
144 |
145 |
146 |
147 | test
148 | test
149 |
150 | check
151 |
152 |
153 |
154 |
155 |
156 | maven-javadoc-plugin
157 | 3.12.0
158 |
159 |
160 |
161 | https://maxmind.github.io/MaxMind-DB-Reader-java/doc/latest/
162 |
163 |
164 | 17
165 | -missing
166 |
167 |
168 |
169 | javadoc-jar
170 | package
171 |
172 | jar
173 |
174 |
175 |
176 |
177 |
178 | org.apache.maven.plugins
179 | maven-assembly-plugin
180 | 3.8.0
181 |
182 |
183 | src/assembly/bin.xml
184 |
185 |
186 |
187 |
188 | package
189 |
190 | single
191 |
192 |
193 |
194 |
195 |
196 | org.apache.maven.plugins
197 | maven-gpg-plugin
198 | 3.2.8
199 |
200 |
201 | sign-artifacts
202 | verify
203 |
204 | sign
205 |
206 |
207 |
208 |
209 |
210 | org.apache.maven.plugins
211 | maven-compiler-plugin
212 | 3.14.1
213 |
214 | 17
215 | 17
216 | 11
217 |
218 |
219 |
220 | org.apache.maven.plugins
221 | maven-jar-plugin
222 | 3.5.0
223 | true
224 |
225 |
226 |
227 | true
228 | true
229 |
230 |
231 |
232 |
233 |
234 | org.apache.maven.plugins
235 | maven-source-plugin
236 | 3.4.0
237 |
238 |
239 | attach-sources
240 | package
241 |
242 | jar-no-fork
243 |
244 |
245 |
246 |
247 |
248 | org.apache.maven.plugins
249 | maven-surefire-plugin
250 | 3.5.4
251 |
252 |
253 | org.codehaus.mojo
254 | versions-maven-plugin
255 | 2.20.1
256 |
257 |
258 | org.sonatype.central
259 | central-publishing-maven-plugin
260 | 0.9.0
261 | true
262 |
263 | central
264 | true
265 |
266 |
267 |
268 |
269 |
270 |
271 | not-windows
272 |
278 |
279 | !Windows
280 |
281 |
282 |
283 |
284 |
289 | org.codehaus.mojo
290 | exec-maven-plugin
291 | 3.6.2
292 |
293 |
294 | initialize
295 | invoke build
296 |
297 | exec
298 |
299 |
300 |
301 |
302 | git
303 | submodule update --init --recursive
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
--------------------------------------------------------------------------------