├── .github ├── dependabot.yml └── workflows │ ├── codeql-analysis.yml │ ├── test.yml │ └── zizmor.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── LICENSE ├── README.dev.md ├── README.md ├── checkstyle-suppressions.xml ├── checkstyle.xml ├── dev-bin └── release.sh ├── pom.xml ├── sample └── Benchmark.java └── src ├── assembly └── bin.xml ├── main └── java │ ├── com │ └── maxmind │ │ └── geoip2 │ │ ├── DatabaseProvider.java │ │ ├── DatabaseReader.java │ │ ├── GeoIp2Provider.java │ │ ├── JsonInjector.java │ │ ├── NetworkDeserializer.java │ │ ├── WebServiceClient.java │ │ ├── WebServiceProvider.java │ │ ├── exception │ │ ├── AddressNotFoundException.java │ │ ├── AuthenticationException.java │ │ ├── GeoIp2Exception.java │ │ ├── HttpException.java │ │ ├── InvalidRequestException.java │ │ ├── OutOfQueriesException.java │ │ └── PermissionRequiredException.java │ │ ├── model │ │ ├── AbstractCityResponse.java │ │ ├── AbstractCountryResponse.java │ │ ├── AbstractResponse.java │ │ ├── AnonymousIpResponse.java │ │ ├── AnonymousPlusResponse.java │ │ ├── AsnResponse.java │ │ ├── CityResponse.java │ │ ├── ConnectionTypeResponse.java │ │ ├── CountryResponse.java │ │ ├── DomainResponse.java │ │ ├── EnterpriseResponse.java │ │ ├── InsightsResponse.java │ │ ├── IpBaseResponse.java │ │ ├── IpRiskResponse.java │ │ └── IspResponse.java │ │ └── record │ │ ├── AbstractNamedRecord.java │ │ ├── AbstractRecord.java │ │ ├── City.java │ │ ├── Continent.java │ │ ├── Country.java │ │ ├── Location.java │ │ ├── MaxMind.java │ │ ├── Postal.java │ │ ├── RepresentedCountry.java │ │ ├── Subdivision.java │ │ └── Traits.java │ └── module-info.java └── test ├── java └── com │ └── maxmind │ └── geoip2 │ ├── DatabaseReaderTest.java │ ├── WebServiceClientTest.java │ ├── json │ └── File.java │ ├── matchers │ ├── CodeMatcher.java │ └── HttpStatusMatcher.java │ └── model │ ├── CityResponseTest.java │ ├── CountryResponseTest.java │ ├── InsightsResponseTest.java │ └── JsonTest.java └── resources └── test-data ├── city0.json ├── country0.json ├── insights0.json └── insights1.json /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: maven 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: daily 12 | -------------------------------------------------------------------------------- /.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@v4 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@v3 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@v3 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@v3 58 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Run tests 2 | on: [push, pull_request] 3 | permissions: {} 4 | jobs: 5 | test: 6 | runs-on: ${{ matrix.os }} 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | distribution: ['zulu'] 11 | os: [ubuntu-latest, windows-latest, macos-latest] 12 | version: [ 11, 17, 21, 22 ] 13 | steps: 14 | - uses: actions/checkout@v4 15 | with: 16 | submodules: true 17 | persist-credentials: false 18 | - uses: actions/setup-java@v4 19 | with: 20 | distribution: ${{ matrix.distribution }} 21 | java-version: ${{ matrix.version }} 22 | - run: mvn test -B 23 | # This is after the test run to work around 24 | # https://issues.apache.org/jira/projects/MJAVADOC/issues/MJAVADOC-736 25 | - run: mvn javadoc:javadoc 26 | -------------------------------------------------------------------------------- /.github/workflows/zizmor.yml: -------------------------------------------------------------------------------- 1 | name: GitHub Actions Security Analysis with zizmor 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | pull_request: 7 | branches: ["**"] 8 | 9 | jobs: 10 | zizmor: 11 | name: zizmor latest via PyPI 12 | runs-on: ubuntu-latest 13 | permissions: 14 | security-events: write 15 | # required for workflows in private repositories 16 | contents: read 17 | actions: read 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@v4 21 | with: 22 | persist-credentials: false 23 | 24 | - name: Install the latest version of uv 25 | uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # 6.1.0 26 | with: 27 | enable-cache: false 28 | 29 | - name: Run zizmor 30 | run: uvx zizmor@1.7.0 --format plain . 31 | env: 32 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *~ 3 | *.iml 4 | *.jar 5 | *.war 6 | *.ear 7 | *.sw? 8 | *.classpath 9 | .gh-pages 10 | .idea 11 | .pmd 12 | .project 13 | .settings 14 | doc 15 | hs_err*.log 16 | pom.xml.versionsBackup 17 | target 18 | reports 19 | Test.java 20 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/test/resources/maxmind-db"] 2 | path = src/test/resources/maxmind-db 3 | url = https://github.com/maxmind/MaxMind-DB 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | ========= 3 | 4 | 4.3.1 (2025-05-28) 5 | ------------------ 6 | 7 | * First release using Central Portal instead of Legacy OSSRH. 8 | * Dependency updates. 9 | 10 | 4.3.0 (2025-05-05) 11 | ------------------ 12 | 13 | * Support for the GeoIP Anonymous Plus database has been added. To do a 14 | lookup in this database, use the `anonymousPlus` method on 15 | `DatabaseReader`. 16 | * `getMetroCode` in the `Location` model has been deprecated. The code 17 | values are no longer being maintained. 18 | 19 | 4.2.1 (2024-09-20) 20 | ------------------ 21 | 22 | * Dependency updates: 23 | * `maxmind-db` was upgraded to 3.1.1. 24 | * Jackson was upgraded to 2.17.2. 25 | * Added missing API documentation. 26 | 27 | 4.2.0 (2023-12-05) 28 | ------------------ 29 | 30 | * A `WebServiceProvider` interface has been added to facilitate mocking of 31 | `WebServiceClient`. Requested by Evan Chrisinger. GitHub #359. 32 | * The GeoIP2 IP Risk database has been discontinued. Methods and classes 33 | related to it have been deprecated. 34 | * The `fromString` static method on the `ConnectionType` enum now has 35 | the `JsonCreator` annotation so that it is used when deserializing. 36 | This will prevent new additions in the future from causing a 37 | deserialization error. 38 | * The `isAnycast()` method was added to `com.maxmind.geoip2.record.Traits`. 39 | This returns `true` if the IP address belongs to an [anycast 40 | network](https://en.wikipedia.org/wiki/Anycast). This is available for the 41 | GeoIP2 Country, City Plus, and Insights web services and the GeoIP2 Country, 42 | City, and Enterprise databases. 43 | 44 | 4.1.0 (2023-07-28) 45 | ------------------ 46 | 47 | * Added `SATELLITE` to the `ConnectionType` enum. 48 | 49 | 4.0.1 (2023-03-02) 50 | ------------------ 51 | 52 | * `com.maxmind.db` is now a transitive dependency of this Java module. 53 | 54 | 4.0.0 (2022-12-12) 55 | ------------------ 56 | 57 | * This library is now a Java module. 58 | * Added support for the GeoIP2 IP Risk database. 59 | 60 | 3.0.2 (2022-10-31) 61 | ------------------ 62 | 63 | * Updated Jackson and `maxmind-db` dependencies. 64 | 65 | 3.0.1 (2022-03-29) 66 | ------------------ 67 | 68 | * Updated Jackson dependencies to address CVE-2020-36518. Pull request by 69 | slunker. GitHub #306. 70 | * Minor doc updates. 71 | 72 | 3.0.0 (2022-01-24) 73 | ------------------ 74 | 75 | * Java 11 or greater is now required. 76 | * Apache HttpClient has been replaced with `java.net.http.HttpClient`. 77 | * The `close()` method on `WebServiceClient` is now deprecated. It 78 | no longer does anything. 79 | * On `WebServiceClient.Builder`: 80 | * `connectTimeout(int)` has been deprecated in favor of 81 | `connectTimeout(Duration)`. 82 | * `readTimeout(int)` has been deprecated in favor of 83 | `requestTimeout(Duration)`. 84 | * `proxy(Proxy)` has been deprecated in favor of `proxy(ProxySelector)`. 85 | * On `HttpException` and `InvalidRequestException`, `getUrl()` has been 86 | deprecated in favor of `getUri()`. Constructors that took a `URL` have 87 | been replaced with the equivalent taking a `URI`. 88 | * Deprecated constructors on model and trait classes were removed. 89 | * Model data types were updated to better reflect database data types. In 90 | particular: 91 | * `getGeoNameId()` on `City`, `Continent`, `Country`, `RepresentedCountry`, 92 | and `Subdivision` now returns a `Long` rather than an `Integer`. 93 | * `getAutonomousSystemNumber()` on `AsnResponse` and `Traits` now returns 94 | a `Long` rather than an `Integer`. 95 | 96 | 2.16.1 (2021-11-18) 97 | ------------------- 98 | 99 | * Added `JsonProperty` annotations to `getMobileCountryCode()` and 100 | `getMobileNetworkCode()` so that it is possible to serialize the 101 | object as JSON and then deserialize without losing data. 102 | 103 | 2.16.0 (2021-11-18) 104 | ------------------- 105 | 106 | * Support for mobile country code (MCC) and mobile network codes (MNC) was 107 | added for the GeoIP2 ISP and Enterprise databases as well as the GeoIP2 108 | City and Insights web services. `getMobileCountryCode()` and 109 | `getMobileNetworkCode()` were added to `com.maxmind.geoip2.model.IspResponse` 110 | for the GeoIP2 ISP database and `com.maxmind.geoip2.record.Traits` for the 111 | Enterprise database and the GeoIP2 City and Insights web services. We expect 112 | this data to be available by late January, 2022. 113 | * Deprecated model constructors that exist for backwards compatibility. 114 | These constructors are not generally used by users of this library 115 | directly except perhaps when mocking the reader in tests. 116 | 117 | 2.15.0 (2020-10-14) 118 | ------------------- 119 | 120 | * No changes since 2.15.0-rc1. 121 | 122 | 2.15.0-rc1 (2020-09-29) 123 | ----------------------- 124 | 125 | * The HTTP client now allows up to 20 connections to be active at once. 126 | Previously the limit was 2. 127 | * Update `maxmind-db` dependency to a new version that no longer uses 128 | Jackson. This improves database lookup performance. 129 | * The `isResidentialProxy()` method was added to 130 | `com.maxmind.geoip2.model.AnonymousIpResponse` and 131 | `com.maxmind.geoip2.record.Traits` for use with the Anonymous IP database 132 | and GeoIP2 Precision insights. 133 | 134 | 2.14.0 (2020-06-15) 135 | ------------------- 136 | 137 | * Update `maxmind-db` dependency to reduce locking when being used from 138 | multiple threads and to improve the exceptions thrown on an invalid 139 | database. 140 | * Update Jackson dependencies. 141 | 142 | 2.13.1 (2020-03-03) 143 | ------------------- 144 | 145 | * Update `maxmind-db` dependency to fix handling of long strings in the 146 | database. Reported by Dongmin Yu. GitHub #181. 147 | * Update Jackson dependencies. 148 | 149 | 2.13.0 (2019-12-18) 150 | ------------------- 151 | 152 | * IMPORTANT: Java 8 is now required. If you need Java 7 support, please 153 | continue using 2.12.0. 154 | * `DatabaseReader` now provides the methods that return an `Optional` rather 155 | than throwing an exception when the record is not found in the database. These 156 | methods are prefixed with "try". Closes #28. Pull request by Luke Butters. 157 | GitHub #147. 158 | * `getNetwork()` methods have been added to the various response models. These 159 | return a `com.maxmind.db.Network` object representing the largest network 160 | where all the fields besides the IP address are the same. 161 | * Updated documentation of anonymizer methods `isAnonymousVpn()` and 162 | `isHostingProvider()` to be more descriptive. 163 | * The `DatabaseReader` methods `city()` and `country()` can now be called on 164 | the Enterprise database and the `country()` method can be called on City 165 | databases. Request by Gergely Boromissza. GitHub #132. 166 | * New `getStaticIpScore()` and `getUserCount()` methods were added to 167 | `com.maxmind.geoip2.record.Traits` for use with GeoIP2 Precision Insights. 168 | They represent a measure of how static or dynamic an IP address is, and an 169 | estimate of the number of users sharing a given address or network, 170 | respectively. 171 | 172 | 2.12.0 (2018-04-11) 173 | ------------------- 174 | 175 | * Rename `userId` to `accountId` in various places and support the future error 176 | codes `ACCOUNT_ID_REQUIRED` and `ACCOUNT_ID_UNKNOWN`. 177 | 178 | 2.11.0 (2018-01-19) 179 | ------------------ 180 | 181 | * The web service client now correctly handles a proxy of `Proxy.NO_PROXY`. 182 | * The `isInEuropeanUnion()` method was added to 183 | `com.maxmind.geoip2.record.Country`. This returns `true` if the country 184 | is a member state of the European Union. 185 | 186 | 2.10.0 (2017-10-27) 187 | ------------------- 188 | 189 | * The following new anonymizer methods were added to 190 | `com.maxmind.geoip2.record.Traits` for use with GeoIP2 Precision Insights: 191 | `isAnonymous()`, `isAnonymousVpn()`, `isHostingProvider()`, `isPublicProxy()`, 192 | and `isTorExitNode()`. 193 | 194 | 2.9.0 (2017-05-08) 195 | ------------------ 196 | 197 | * Added support for GeoLite2 ASN database. 198 | 199 | 2.8.1 (2017-02-22) 200 | ------------------ 201 | 202 | * Update `maxmind-db` dependency to fix `jackson-databind` version range 203 | issue. Closes GitHub #77. 204 | * Update most other dependencies. 205 | 206 | 2.8.0 (2016-09-15) 207 | ------------------ 208 | 209 | * All changes included in 2.8.0-rc1. 210 | * Updated documentation to clarify what the accuracy radius refers to. 211 | 212 | 2.8.0-rc1 (2016-06-20) 213 | ---------------------- 214 | 215 | * IMPORTANT: Java 7 is now required. If you need Java 6 support, please 216 | continue using 2.7.0 or earlier. 217 | * This library no longer uses Google HTTP Client. It now directly uses 218 | Apache HttpClient. Closes #40, #66. 219 | * `WebServiceClient` now implements `Closeable`. A pool of connections will be 220 | kept alive to be used across requests. To ensure all connections are closed 221 | when the object goes out of scope, call `close()` or use the 222 | try-with-resource statement as appropriate. 223 | * Setting of a proxy for the `WebServiceClient` is now supported by the 224 | `proxy(Proxy)` builder method. 225 | * Updated documentation to reflect that the accuracy radius is now included 226 | in City. 227 | * Updated dependencies. 228 | 229 | 2.7.0 (2016-04-15) 230 | ------------------ 231 | 232 | * Added support for the GeoIP2 Enterprise database. 233 | 234 | 2.6.0 (2016-01-13) 235 | ------------------ 236 | 237 | * This release was updated to 1.2.0 of the MaxMind DB reader, which includes 238 | faster caching with fewer allocations. 239 | * The IP addresses in the database models are now injected via Jackson rather 240 | than being added to the `JsonNode` before deserialization. Pull requests by 241 | Viktor Szathmáry. GitHub #56. 242 | 243 | 2.5.0 (2016-01-04) 244 | ------------------ 245 | 246 | * The database reader now supports pluggable caching of the decoded data. By 247 | default, no caching is performed. Please see the `README.md` file or the API 248 | docs for information on how to enable caching. Pull requests by Viktor 249 | Szathmáry. GitHub #55. 250 | 251 | 2.4.0 (2015-12-21) 252 | ------------------ 253 | 254 | * Jackson now uses the constructors on model classes when mapping JSON and 255 | database records to them rather than overriding the access modifiers on 256 | them. Pull request by Martijn van Groningen. GitHub #51 & #52. 257 | * The format of the output of the `toString()` methods in the models has 258 | changed to better represent the values returned by the databases and web 259 | services. `toString()` should be only used for debugging and diagnostics. 260 | Do not try to parse it. If you want the contents of the model as a machine- 261 | readable string, use `toJson()`. 262 | * This release depends on version 1.0.1 of the MaxMind DB reader, which 263 | includes several performance enhancements from by Viktor Szathmáry. 264 | 265 | 2.3.1 (2015-07-07) 266 | ------------------ 267 | 268 | * No code changes in this release 269 | * Fix for version number in pom.xml example in README.md 270 | * Slight documentation improvement referring to MaxMind-DB-Reader-java 271 | 272 | 2.3.0 (2015-06-29) 273 | ------------------ 274 | 275 | * Add support for the `average_income` and `population_density` fields. 276 | * The `isAnonymousProxy()` and `isSatelliteProvider()` methods on 277 | `com.maxmind.geoip2.record.Traits` have been deprecated. Please use our 278 | [GeoIP2 Anonymous IP database](https://www.maxmind.com/en/geoip2-anonymous- 279 | ip-database) to determine whether an IP address is used by an anonymizing 280 | service. 281 | 282 | 2.2.0 (2015-04-24) 283 | ------------------ 284 | 285 | * A `DatabaseProvider` interface has been added to facilitate mocking of 286 | `DatabaseReader`. Pull request by Yonatan Most. GitHub #34. 287 | * A `getLeastSpecificSubdivision()` method has been added to the 288 | `CityResponse` and `InsightsResponse` model classes. This returns the 289 | least specific subdivision for the location, e.g., England for Oxford, 290 | GB. Pull request by Daniel Kaneider. GitHub #35. 291 | * The `InsightsResponse` and `Location` classes are no longer declared final. 292 | * `AbstractResponse` is now declared `abstract`. 293 | 294 | 2.1.0 (2014-11-06) 295 | ------------------ 296 | 297 | * Added support for the GeoIP2 Anonymous IP database. The `DatabaseReader` 298 | class now has an `anonymousIp()` method which returns an 299 | `AnonymousIpResponse` object. 300 | 301 | 2.0.0 (2014-09-29) 302 | ------------------ 303 | 304 | * First production release. 305 | 306 | 0.10.0 (2014-09-23) 307 | ------------------- 308 | 309 | * The deprecated `cityIspOrg()` and `omni()` methods have been removed from 310 | `DatabaseReader` and `WebServiceClient`. 311 | * The lookup methods on `DatabaseReader` now throw an 312 | `UnsupportedOperationException` if the incorrect method is used for the 313 | database. 314 | * `DatabaseReader` now provides the metadata for the database through the 315 | `getDatabase()` method. 316 | * All of our dependencies were updated to the latest available version. 317 | 318 | 0.9.0 (2014-09-02) 319 | ------------------ 320 | 321 | * The `timeout` setter on `WebServiceClient.Builder` was renamed to 322 | `connectTimeout` and a `readTimeout` setter was added. The former timeout 323 | sets the timeout to establish a connection and the latter sets the timeout 324 | for reading from an established connection. 325 | 326 | 0.8.1 (2014-08-27) 327 | ------------------ 328 | 329 | * Updated to depend on the latest version of `com.maxmind.db` and 330 | `com.fasterxml.jackson.core`. 331 | 332 | 0.8.0 (2014-07-22) 333 | ------------------ 334 | 335 | * The web service client API has been updated for the v2.1 release of the web 336 | service. In particular, the `cityIspOrg` and `omni` methods on 337 | `WebServiceClient` have been deprecated. The `city` method now provides all 338 | of the data formerly provided by `cityIspOrg`, and the `omni` method has 339 | been replaced by the `insights` method. 340 | * Support was added for the GeoIP2 Connection Type, Domain, and ISP databases. 341 | 342 | 0.7.2 (2014-06-02) 343 | ------------------ 344 | 345 | * Updated to version 0.3.3 of `maxmind-db`, which fixes a potential resource 346 | leak when used with a thread pool. 347 | * Updated Google HTTP Client dependency. 348 | * The Maven build was updated to include a zip file with all dependencies. 349 | 350 | 0.7.1 (2014-04-02) 351 | ------------------ 352 | 353 | * Added `toJson` method to response objects. 354 | * Fixed a potential issue when using the `WebServiceClient` in multi-threaded 355 | applications. 356 | * Updated documentation. 357 | 358 | 0.7.0 (2013-11-05) 359 | ------------------ 360 | 361 | * Renamed `getSubdivisionsList` to `getSubdivisions` on `AbstractNamedRecord`. 362 | * An `InputStream` constructor was added to the `DatabaseReader.Builder` 363 | class. This reads the stream into memory as if it was using the 364 | `FileMode.MEMORY` mode. Patch by Matthew Daniel. 365 | * The source code is now attached during packaging. Patch by Matthew Daniel. 366 | 367 | 0.6.0 (2013-10-23) 368 | ------------------ 369 | 370 | * IMPORTANT API CHANGE: The `DatabaseReader` class now uses a builder to 371 | construct the object. The class constructor on `DatabaseReader` is no longer 372 | public. 373 | * Renamed the `languages` method on the `WebServiceClient.Builder` to 374 | `locales`. 375 | 376 | 0.5.0 (2013-10-17) 377 | ------------------ 378 | 379 | * Reorganized the response and record classes. The response classes end 380 | with `Response`. The record classes no longer end in `Record`. 381 | 382 | 0.4.1 (2013-08-16) 383 | ------------------ 384 | 385 | * Set the user-agent header to include API information. 386 | * Updated documentation. 387 | * Removed unused dependency from Maven POM. 388 | 389 | 0.4.0 (2013-07-08) 390 | ------------------ 391 | 392 | * Removed class hierarchy among web-service endpoint models. 393 | * Refactored database-reader API to more closely match the web-service API. 394 | Created a Java interface for the two classes. 395 | 396 | 0.3.0 (2013-06-27) 397 | ------------------ 398 | 399 | * Reorganized the classes. `Client` was renamed `WebServiceClient` and moved 400 | to `com.maxmind.geoip2`. Record classes now have a suffix of "Record". 401 | The product classes (e.g., Omni) were renamed to their product name with 402 | no "Lookup" suffix. 403 | * Additional specific exceptions were added to replace the general 404 | `WebServiceException`. 405 | * A `DatabaseReader` class was added to the distribution. This reads GeoIP2 406 | databases and returns similar product object to `WebServiceClient`. 407 | 408 | 0.2.0 (2013-06-13) 409 | ------------------ 410 | 411 | * Replaced the public constructor on `Client` with a `Builder` class. 412 | 413 | 0.1.1 (2013-06-10) 414 | ------------------ 415 | 416 | * First official beta release. 417 | * Documentation updates and corrections. 418 | * Changed license to Apache License, Version 2.0. 419 | 420 | 0.1.0 (2013-05-21) 421 | ------------------ 422 | 423 | * Initial release 424 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.dev.md: -------------------------------------------------------------------------------- 1 | See the [`README.dev.md` in `minfraud-api-java`](https://github.com/maxmind/minfraud-api-java/blob/main/README.dev.md). 2 | -------------------------------------------------------------------------------- /checkstyle-suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /dev-bin/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu -o pipefail 4 | 5 | changelog=$(cat CHANGELOG.md) 6 | 7 | regex=' 8 | ([0-9]+\.[0-9]+\.[0-9]+[a-zA-Z0-9\-]*) \(([0-9]{4}-[0-9]{2}-[0-9]{2})\) 9 | -* 10 | 11 | ((.| 12 | )*) 13 | ' 14 | 15 | if [[ ! $changelog =~ $regex ]]; then 16 | echo "Could not find date line in change log!" 17 | exit 1 18 | fi 19 | 20 | version="${BASH_REMATCH[1]}" 21 | date="${BASH_REMATCH[2]}" 22 | notes="$(echo "${BASH_REMATCH[3]}" | sed -n -e '/^[0-9]\+\.[0-9]\+\.[0-9]\+/,$!p')" 23 | 24 | if [[ "$date" != $(date +"%Y-%m-%d") ]]; then 25 | echo "$date is not today!" 26 | exit 1 27 | fi 28 | 29 | tag="v$version" 30 | 31 | if [ -n "$(git status --porcelain)" ]; then 32 | echo ". is not clean." >&2 33 | exit 1 34 | fi 35 | 36 | if [ ! -d .gh-pages ]; then 37 | echo "Checking out gh-pages in .gh-pages" 38 | git clone -b gh-pages git@github.com:maxmind/GeoIP2-java.git .gh-pages 39 | pushd .gh-pages 40 | else 41 | echo "Updating .gh-pages" 42 | pushd .gh-pages 43 | git pull 44 | fi 45 | 46 | if [ -n "$(git status --porcelain)" ]; then 47 | echo ".gh-pages is not clean" >&2 48 | exit 1 49 | fi 50 | 51 | popd 52 | 53 | mvn versions:display-plugin-updates 54 | mvn versions:display-dependency-updates 55 | 56 | read -r -n 1 -p "Continue given above dependencies? (y/n) " should_continue 57 | 58 | if [ "$should_continue" != "y" ]; then 59 | echo "Aborting" 60 | exit 1 61 | fi 62 | 63 | mvn test 64 | 65 | read -r -n 1 -p "Continue given above tests? (y/n) " should_continue 66 | 67 | if [ "$should_continue" != "y" ]; then 68 | echo "Aborting" 69 | exit 1 70 | fi 71 | 72 | page=.gh-pages/index.md 73 | cat < $page 74 | --- 75 | layout: default 76 | title: MaxMind GeoIP2 Java API 77 | language: java 78 | version: $tag 79 | --- 80 | 81 | EOF 82 | 83 | mvn versions:set -DnewVersion="$version" 84 | 85 | perl -pi -e "s/(?<=)[^<]*/$version/" README.md 86 | perl -pi -e "s/(?<=com\.maxmind\.geoip2\:geoip2\:)\d+\.\d+\.\d+([\w\-]+)?/$version/" README.md 87 | 88 | cat README.md >> $page 89 | 90 | git diff 91 | 92 | read -r -n 1 -p "Commit changes? " should_commit 93 | if [ "$should_commit" != "y" ]; then 94 | echo "Aborting" 95 | exit 1 96 | fi 97 | git add README.md pom.xml 98 | git commit -m "Preparing for $version" 99 | 100 | mvn clean deploy 101 | 102 | rm -fr ".gh-pages/doc/$tag" 103 | cp -r target/reports/apidocs ".gh-pages/doc/$tag" 104 | rm .gh-pages/doc/latest 105 | ln -fs "$tag" .gh-pages/doc/latest 106 | 107 | pushd .gh-pages 108 | 109 | git add doc/ 110 | git commit -m "Updated for $tag" -a 111 | 112 | echo "Release notes for $version: 113 | 114 | $notes 115 | 116 | " 117 | read -r -n 1 -p "Push to origin? " should_push 118 | 119 | if [ "$should_push" != "y" ]; then 120 | echo "Aborting" 121 | exit 1 122 | fi 123 | 124 | git push 125 | 126 | popd 127 | 128 | git push 129 | 130 | gh release create --target "$(git branch --show-current)" -t "$version" -n "$notes" "$tag" \ 131 | "target/geoip2-$version-with-dependencies.zip" \ 132 | "target/geoip2-$version-with-dependencies.zip.asc" 133 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | com.maxmind.geoip2 5 | geoip2 6 | 4.3.1 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 | com.maxmind.db 42 | maxmind-db 43 | 3.2.0 44 | 45 | 46 | com.fasterxml.jackson.core 47 | jackson-databind 48 | 2.19.0 49 | 50 | 51 | com.fasterxml.jackson.datatype 52 | jackson-datatype-jsr310 53 | 2.19.0 54 | 55 | 56 | com.fasterxml.jackson.core 57 | jackson-core 58 | 2.19.0 59 | 60 | 61 | com.fasterxml.jackson.core 62 | jackson-annotations 63 | 2.19.0 64 | 65 | 66 | org.wiremock 67 | wiremock 68 | 3.13.0 69 | test 70 | 71 | 72 | com.fasterxml.jackson.jr 73 | jackson-jr-objects 74 | 2.19.0 75 | test 76 | 77 | 78 | com.jcabi 79 | jcabi-matchers 80 | 1.8.0 81 | test 82 | 83 | 84 | org.junit.jupiter 85 | junit-jupiter 86 | 5.13.1 87 | test 88 | 89 | 90 | 91 | UTF-8 92 | 93 | 94 | 95 | 96 | org.apache.maven.plugins 97 | maven-enforcer-plugin 98 | 3.5.0 99 | 100 | 101 | enforce-maven 102 | 103 | enforce 104 | 105 | 106 | 107 | 108 | 3.6.3 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | org.apache.maven.plugins 117 | maven-checkstyle-plugin 118 | 3.6.0 119 | 120 | true 121 | checkstyle.xml 122 | checkstyle-suppressions.xml 123 | warning 124 | 125 | 126 | 127 | com.puppycrawl.tools 128 | checkstyle 129 | 10.25.0 130 | 131 | 132 | 133 | 134 | test 135 | test 136 | 137 | check 138 | 139 | 140 | 141 | 142 | 143 | maven-javadoc-plugin 144 | 3.11.2 145 | 146 | 147 | 148 | https://maxmind.github.io/MaxMind-DB-Reader-java/doc/latest/ 149 | 150 | 151 | 11 152 | -missing 153 | 154 | 155 | 156 | javadoc-jar 157 | package 158 | 159 | jar 160 | 161 | 162 | 163 | 164 | 165 | org.apache.maven.plugins 166 | maven-assembly-plugin 167 | 3.7.1 168 | 169 | 170 | src/assembly/bin.xml 171 | 172 | 173 | 174 | 175 | package 176 | 177 | single 178 | 179 | 180 | 181 | 182 | 183 | org.apache.maven.plugins 184 | maven-gpg-plugin 185 | 3.2.7 186 | 187 | 188 | sign-artifacts 189 | verify 190 | 191 | sign 192 | 193 | 194 | 195 | 196 | 197 | org.apache.maven.plugins 198 | maven-compiler-plugin 199 | 3.14.0 200 | 201 | 11 202 | 11 203 | 11 204 | 205 | 206 | 207 | org.apache.maven.plugins 208 | maven-jar-plugin 209 | 3.4.2 210 | true 211 | 212 | 213 | 214 | true 215 | true 216 | 217 | 218 | 219 | 220 | 221 | org.apache.maven.plugins 222 | maven-source-plugin 223 | 3.3.1 224 | 225 | 226 | attach-sources 227 | package 228 | 229 | jar-no-fork 230 | 231 | 232 | 233 | 234 | 235 | org.apache.maven.plugins 236 | maven-surefire-plugin 237 | 3.5.3 238 | 239 | 240 | org.codehaus.mojo 241 | versions-maven-plugin 242 | 2.18.0 243 | 244 | 245 | org.sonatype.central 246 | central-publishing-maven-plugin 247 | 0.7.0 248 | true 249 | 250 | central 251 | true 252 | 253 | 254 | 255 | 256 | 257 | 258 | not-windows 259 | 265 | 266 | !Windows 267 | 268 | 269 | 270 | 271 | 276 | org.codehaus.mojo 277 | exec-maven-plugin 278 | 3.5.1 279 | 280 | 281 | initialize 282 | invoke build 283 | 284 | exec 285 | 286 | 287 | 288 | 289 | git 290 | submodule update --init --recursive 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | sonatype-nexus-staging 300 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 301 | 302 | 303 | 304 | -------------------------------------------------------------------------------- /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/assembly/bin.xml: -------------------------------------------------------------------------------- 1 | 2 | with-dependencies 3 | 4 | zip 5 | 6 | 7 | 8 | false 9 | runtime 10 | lib 11 | 12 | 13 | 14 | 15 | ${project.basedir} 16 | / 17 | 18 | README.md 19 | LICENSE* 20 | CHANGELOG* 21 | 22 | 23 | 24 | ${project.basedir}/target 25 | lib 26 | 27 | *.jar 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /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 | * @deprecated This database has been discontinued. 93 | */ 94 | @Deprecated 95 | IpRiskResponse ipRisk(InetAddress ipAddress) throws IOException, 96 | GeoIp2Exception; 97 | 98 | /** 99 | * Look up an IP address in a GeoIP2 IP Risk database. 100 | * 101 | * @param ipAddress IPv4 or IPv6 address to lookup. 102 | * @return an IPRiskResponse for the requested IP address or empty if it is not in the DB. 103 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP 104 | * @throws java.io.IOException if there is an IO error 105 | * @deprecated This database has been discontinued. 106 | */ 107 | @Deprecated 108 | Optional tryIpRisk(InetAddress ipAddress) throws IOException, 109 | GeoIp2Exception; 110 | 111 | /** 112 | * Look up an IP address in a GeoLite2 ASN database. 113 | * 114 | * @param ipAddress IPv4 or IPv6 address to lookup. 115 | * @return an IspResponse for the requested IP address. 116 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP 117 | * @throws java.io.IOException if there is an IO error 118 | */ 119 | AsnResponse asn(InetAddress ipAddress) throws IOException, 120 | GeoIp2Exception; 121 | 122 | /** 123 | * Look up an IP address in a GeoLite2 ASN database. 124 | * 125 | * @param ipAddress IPv4 or IPv6 address to lookup. 126 | * @return an IspResponse for the requested IP address or empty if it is not in the DB. 127 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP 128 | * @throws java.io.IOException if there is an IO error 129 | */ 130 | Optional tryAsn(InetAddress ipAddress) throws IOException, 131 | GeoIp2Exception; 132 | 133 | /** 134 | * Look up an IP address in a GeoIP2 Connection Type database. 135 | * 136 | * @param ipAddress IPv4 or IPv6 address to lookup. 137 | * @return a ConnectTypeResponse for the requested IP address. 138 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP 139 | * @throws java.io.IOException if there is an IO error 140 | */ 141 | ConnectionTypeResponse connectionType(InetAddress ipAddress) 142 | throws IOException, GeoIp2Exception; 143 | 144 | /** 145 | * Look up an IP address in a GeoIP2 Connection Type database. 146 | * 147 | * @param ipAddress IPv4 or IPv6 address to lookup. 148 | * @return a ConnectTypeResponse for the requested IP address or empty if it is not in the DB. 149 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP 150 | * @throws java.io.IOException if there is an IO error 151 | */ 152 | Optional tryConnectionType(InetAddress ipAddress) 153 | throws IOException, GeoIp2Exception; 154 | 155 | /** 156 | * Look up an IP address in a GeoIP2 Domain database. 157 | * 158 | * @param ipAddress IPv4 or IPv6 address to lookup. 159 | * @return a DomainResponse for the requested IP address. 160 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP 161 | * @throws java.io.IOException if there is an IO error 162 | */ 163 | DomainResponse domain(InetAddress ipAddress) throws IOException, 164 | GeoIp2Exception; 165 | 166 | /** 167 | * Look up an IP address in a GeoIP2 Domain database. 168 | * 169 | * @param ipAddress IPv4 or IPv6 address to lookup. 170 | * @return a DomainResponse for the requested IP address or empty if it is not in the DB. 171 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP 172 | * @throws java.io.IOException if there is an IO error 173 | */ 174 | Optional tryDomain(InetAddress ipAddress) throws IOException, 175 | GeoIp2Exception; 176 | 177 | /** 178 | * Look up an IP address in a GeoIP2 Enterprise database. 179 | * 180 | * @param ipAddress IPv4 or IPv6 address to lookup. 181 | * @return an EnterpriseResponse for the requested IP address. 182 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP 183 | * @throws java.io.IOException if there is an IO error 184 | */ 185 | EnterpriseResponse enterprise(InetAddress ipAddress) throws IOException, 186 | GeoIp2Exception; 187 | 188 | /** 189 | * Look up an IP address in a GeoIP2 Enterprise database. 190 | * 191 | * @param ipAddress IPv4 or IPv6 address to lookup. 192 | * @return an EnterpriseResponse for the requested IP address or empty if it is not in the DB. 193 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP 194 | * @throws java.io.IOException if there is an IO error 195 | */ 196 | Optional tryEnterprise(InetAddress ipAddress) throws IOException, 197 | GeoIp2Exception; 198 | 199 | /** 200 | * Look up an IP address in a GeoIP2 ISP database. 201 | * 202 | * @param ipAddress IPv4 or IPv6 address to lookup. 203 | * @return an IspResponse for the requested IP address. 204 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP 205 | * @throws java.io.IOException if there is an IO error 206 | */ 207 | IspResponse isp(InetAddress ipAddress) throws IOException, 208 | GeoIp2Exception; 209 | 210 | /** 211 | * Look up an IP address in a GeoIP2 ISP database. 212 | * 213 | * @param ipAddress IPv4 or IPv6 address to look up or empty if it is not in the DB. 214 | * @return an IspResponse for the requested IP address. 215 | * @throws com.maxmind.geoip2.exception.GeoIp2Exception if there is an error looking up the IP 216 | * @throws java.io.IOException if there is an IO error 217 | */ 218 | Optional tryIsp(InetAddress ipAddress) throws IOException, 219 | GeoIp2Exception; 220 | } 221 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/GeoIp2Provider.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 java.io.IOException; 7 | import java.net.InetAddress; 8 | 9 | /** 10 | * Interface for GeoIP2 providers. 11 | */ 12 | public interface GeoIp2Provider { 13 | 14 | /** 15 | * @param ipAddress IPv4 or IPv6 address to lookup. 16 | * @return A Country model for the requested IP address. 17 | * @throws GeoIp2Exception if there is an error looking up the IP 18 | * @throws IOException if there is an IO error 19 | */ 20 | CountryResponse country(InetAddress ipAddress) throws IOException, 21 | GeoIp2Exception; 22 | 23 | /** 24 | * @param ipAddress IPv4 or IPv6 address to lookup. 25 | * @return A City model for the requested IP address. 26 | * @throws GeoIp2Exception if there is an error looking up the IP 27 | * @throws IOException if there is an IO error 28 | */ 29 | CityResponse city(InetAddress ipAddress) throws IOException, 30 | GeoIp2Exception; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/JsonInjector.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2; 2 | 3 | import com.fasterxml.jackson.databind.BeanProperty; 4 | import com.fasterxml.jackson.databind.DeserializationContext; 5 | import com.fasterxml.jackson.databind.InjectableValues; 6 | import com.maxmind.db.Network; 7 | import com.maxmind.geoip2.record.Traits; 8 | import java.util.List; 9 | 10 | class JsonInjector extends InjectableValues { 11 | private final List locales; 12 | private final String ip; 13 | private final Network network; 14 | 15 | public JsonInjector(List locales, String ip, Network network) { 16 | this.locales = locales; 17 | this.ip = ip; 18 | this.network = network; 19 | } 20 | 21 | @Override 22 | public Object findInjectableValue(Object valueId, DeserializationContext ctxt, 23 | BeanProperty forProperty, Object beanInstance) { 24 | if ("locales".equals(valueId)) { 25 | return locales; 26 | } 27 | if ("ip_address".equals(valueId)) { 28 | return ip; 29 | } 30 | if ("network".equals(valueId)) { 31 | return network; 32 | } 33 | if ("traits".equals(valueId)) { 34 | return new Traits(ip, network); 35 | } 36 | return null; 37 | } 38 | } -------------------------------------------------------------------------------- /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 class NetworkDeserializer extends StdDeserializer { 15 | 16 | /** 17 | * Constructs a @{code NetworkDeserializer} object. 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( 34 | JsonParser jsonparser, DeserializationContext context) 35 | throws IOException { 36 | 37 | String cidr = jsonparser.getText(); 38 | if (cidr == null) { 39 | return null; 40 | } 41 | String[] parts = cidr.split("/", 2); 42 | if (parts.length != 2) { 43 | throw new RuntimeException("Invalid cidr format: " + cidr); 44 | } 45 | int prefixLength = Integer.parseInt(parts[1]); 46 | try { 47 | return new Network(InetAddress.getByName(parts[0]), prefixLength); 48 | } catch (UnknownHostException e) { 49 | throw new RuntimeException(e); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/exception/AddressNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.exception; 2 | 3 | /** 4 | * This exception is thrown when the IP address is not found in the database. 5 | * This generally means that the address was a private or reserved address. 6 | */ 7 | public final class AddressNotFoundException extends GeoIp2Exception { 8 | 9 | private static final long serialVersionUID = -639962574626980783L; 10 | 11 | /** 12 | * @param message A message explaining the cause of the error. 13 | */ 14 | public AddressNotFoundException(String message) { 15 | super(message); 16 | } 17 | 18 | /** 19 | * @param message A message explaining the cause of the error. 20 | * @param e The cause of the exception. 21 | */ 22 | public AddressNotFoundException(String message, Throwable e) { 23 | super(message, e); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/exception/AuthenticationException.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.exception; 2 | 3 | /** 4 | * This exception is thrown when there is an authentication error. 5 | */ 6 | public final class AuthenticationException extends GeoIp2Exception { 7 | 8 | private static final long serialVersionUID = 2255398691576141427L; 9 | 10 | /** 11 | * @param message A message explaining the cause of the error. 12 | */ 13 | public AuthenticationException(String message) { 14 | super(message); 15 | } 16 | 17 | /** 18 | * @param message A message explaining the cause of the error. 19 | * @param e The cause of the exception. 20 | */ 21 | public AuthenticationException(String message, Throwable e) { 22 | super(message, e); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/exception/GeoIp2Exception.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.exception; 2 | 3 | /** 4 | * This class represents a generic GeoIP2 error. All other exceptions thrown by 5 | * the GeoIP2 API subclass this exception 6 | */ 7 | public class GeoIp2Exception extends Exception { 8 | 9 | private static final long serialVersionUID = -1923104535309628719L; 10 | 11 | /** 12 | * @param message A message describing the reason why the exception was thrown. 13 | */ 14 | public GeoIp2Exception(String message) { 15 | super(message); 16 | } 17 | 18 | /** 19 | * @param message A message describing the reason why the exception was thrown. 20 | * @param cause The cause of the exception. 21 | */ 22 | public GeoIp2Exception(String message, Throwable cause) { 23 | super(message, cause); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /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.MalformedURLException; 5 | import java.net.URI; 6 | import java.net.URL; 7 | 8 | /** 9 | * This class represents an HTTP transport error. This is not an error returned 10 | * by the web service itself. As such, it is a IOException instead of a 11 | * GeoIp2Exception. 12 | */ 13 | public final class HttpException extends IOException { 14 | private static final long serialVersionUID = -8301101841509056974L; 15 | private final int httpStatus; 16 | private final URI uri; 17 | 18 | /** 19 | * @param message A message describing the reason why the exception was thrown. 20 | * @param httpStatus The HTTP status of the response that caused the exception. 21 | * @param uri The URI queried. 22 | */ 23 | public HttpException(String message, int httpStatus, URI uri) { 24 | super(message); 25 | this.httpStatus = httpStatus; 26 | this.uri = uri; 27 | } 28 | 29 | /** 30 | * @param message A message describing the reason why the exception was thrown. 31 | * @param httpStatus The HTTP status of the response that caused the exception. 32 | * @param uri The URI queried. 33 | * @param cause The cause of the exception. 34 | */ 35 | public HttpException(String message, int httpStatus, URI uri, 36 | Throwable cause) { 37 | super(message, cause); 38 | this.httpStatus = httpStatus; 39 | this.uri = uri; 40 | } 41 | 42 | /** 43 | * @return the HTTP status of the query that caused the exception. 44 | */ 45 | public int getHttpStatus() { 46 | return this.httpStatus; 47 | } 48 | 49 | /** 50 | * @return the URI queried. 51 | */ 52 | public URI getUri() { 53 | return this.uri; 54 | } 55 | 56 | /** 57 | * @return the URL queried. 58 | * @deprecated Use getUri() instead 59 | */ 60 | @Deprecated 61 | public URL getUrl() { 62 | try { 63 | return this.uri.toURL(); 64 | } catch (MalformedURLException e) { 65 | return null; 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/exception/InvalidRequestException.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.exception; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URI; 5 | import java.net.URL; 6 | 7 | /** 8 | * This class represents a non-specific error returned by MaxMind's GeoIP2 web 9 | * service. This occurs when the web service is up and responding to requests, 10 | * but the request sent was invalid in some way. 11 | */ 12 | public final class InvalidRequestException extends GeoIp2Exception { 13 | private static final long serialVersionUID = 8662062420258379643L; 14 | private final String code; 15 | private final URI uri; 16 | 17 | /** 18 | * @param message A message explaining the cause of the error. 19 | * @param code The error code returned by the web service. 20 | * @param uri The URI queried. 21 | */ 22 | public InvalidRequestException(String message, String code, URI uri) { 23 | super(message); 24 | this.uri = uri; 25 | this.code = code; 26 | } 27 | 28 | /** 29 | * @param message A message explaining the cause of the error. 30 | * @param code The error code returned by the web service. 31 | * @param httpStatus The HTTP status of the response. 32 | * @param uri The URI queried. 33 | * @param e The cause of the exception. 34 | */ 35 | public InvalidRequestException(String message, String code, int httpStatus, 36 | URI uri, Throwable e) { 37 | super(message, e); 38 | this.code = code; 39 | this.uri = uri; 40 | } 41 | 42 | /** 43 | * @return The error code returned by the MaxMind web service. 44 | */ 45 | public String getCode() { 46 | return this.code; 47 | } 48 | 49 | /** 50 | * @return the URI queried. 51 | */ 52 | public URI getUri() { 53 | return this.uri; 54 | } 55 | 56 | /** 57 | * @return the URL queried. 58 | * @deprecated Use getUri() instead 59 | */ 60 | @Deprecated 61 | public URL getUrl() { 62 | try { 63 | return this.uri.toURL(); 64 | } catch (MalformedURLException e) { 65 | return null; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/exception/OutOfQueriesException.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.exception; 2 | 3 | /** 4 | * This exception is thrown when your account does not have any queries 5 | * remaining for the called service. 6 | */ 7 | public final class OutOfQueriesException extends GeoIp2Exception { 8 | private static final long serialVersionUID = 3843736987256336967L; 9 | 10 | /** 11 | * @param message A message explaining the cause of the error. 12 | */ 13 | public OutOfQueriesException(String message) { 14 | super(message); 15 | } 16 | 17 | /** 18 | * @param message A message explaining the cause of the error. 19 | * @param e The cause of the exception. 20 | */ 21 | public OutOfQueriesException(String message, Throwable e) { 22 | super(message, e); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/exception/PermissionRequiredException.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.exception; 2 | 3 | 4 | /** 5 | * This exception is thrown when permission is required to use the service. 6 | */ 7 | public final class PermissionRequiredException extends GeoIp2Exception { 8 | /** 9 | * @param message A message explaining the cause of the error. 10 | */ 11 | public PermissionRequiredException(String message) { 12 | super(message); 13 | } 14 | 15 | /** 16 | * @param message A message explaining the cause of the error. 17 | * @param e The cause of the exception. 18 | */ 19 | public PermissionRequiredException(String message, Throwable e) { 20 | super(message, e); 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/model/AbstractCityResponse.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import com.maxmind.db.Network; 5 | import com.maxmind.geoip2.record.City; 6 | import com.maxmind.geoip2.record.Continent; 7 | import com.maxmind.geoip2.record.Country; 8 | import com.maxmind.geoip2.record.Location; 9 | import com.maxmind.geoip2.record.MaxMind; 10 | import com.maxmind.geoip2.record.Postal; 11 | import com.maxmind.geoip2.record.RepresentedCountry; 12 | import com.maxmind.geoip2.record.Subdivision; 13 | import com.maxmind.geoip2.record.Traits; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * Abstract class for models that contain City data. 19 | */ 20 | public abstract class AbstractCityResponse extends AbstractCountryResponse { 21 | 22 | private final City city; 23 | private final Location location; 24 | private final Postal postal; 25 | private final List subdivisions; 26 | 27 | AbstractCityResponse( 28 | City city, 29 | Continent continent, 30 | Country country, 31 | Location location, 32 | MaxMind maxmind, 33 | Postal postal, 34 | Country registeredCountry, 35 | RepresentedCountry representedCountry, 36 | List subdivisions, 37 | Traits traits 38 | ) { 39 | super(continent, country, maxmind, registeredCountry, representedCountry, traits); 40 | this.city = city != null ? city : new City(); 41 | this.location = location != null ? location : new Location(); 42 | this.postal = postal != null ? postal : new Postal(); 43 | this.subdivisions = subdivisions != null ? subdivisions : new ArrayList<>(); 44 | } 45 | 46 | AbstractCityResponse( 47 | AbstractCityResponse response, 48 | String ipAddress, 49 | Network network, 50 | List locales 51 | ) { 52 | super(response, ipAddress, network, locales); 53 | // The response fields will be non-null because of the above 54 | // constructor used during deserializing. 55 | this.city = new City(response.getCity(), locales); 56 | this.location = response.getLocation(); 57 | this.postal = response.getPostal(); 58 | this.subdivisions = mapSubdivisions(response.getSubdivisions(), locales); 59 | } 60 | 61 | private static ArrayList mapSubdivisions( 62 | List subdivisions, 63 | List locales 64 | ) { 65 | ArrayList subdivisions2 = new ArrayList<>(subdivisions.size()); 66 | for (Subdivision subdivision : subdivisions) { 67 | subdivisions2.add(new Subdivision(subdivision, locales)); 68 | } 69 | return subdivisions2; 70 | } 71 | 72 | /** 73 | * @return City record for the requested IP address. 74 | */ 75 | public City getCity() { 76 | return this.city; 77 | } 78 | 79 | /** 80 | * @return Location record for the requested IP address. 81 | */ 82 | public Location getLocation() { 83 | return this.location; 84 | } 85 | 86 | /** 87 | * @return the postal 88 | */ 89 | public Postal getPostal() { 90 | return this.postal; 91 | } 92 | 93 | /** 94 | * @return An {@link List} of {@link Subdivision} objects representing the 95 | * country subdivisions for the requested IP address. The number and 96 | * type of subdivisions varies by country, but a subdivision is 97 | * typically a state, province, county, etc. Subdivisions are 98 | * ordered from most general (largest) to most specific (smallest). 99 | * If the response did not contain any subdivisions, this method 100 | * returns an empty array. 101 | */ 102 | public List getSubdivisions() { 103 | return new ArrayList<>(this.subdivisions); 104 | } 105 | 106 | /** 107 | * @return An object representing the most specific subdivision returned. If 108 | * the response did not contain any subdivisions, this method 109 | * returns an empty {@link Subdivision} object. 110 | */ 111 | @JsonIgnore 112 | public Subdivision getMostSpecificSubdivision() { 113 | if (this.subdivisions.isEmpty()) { 114 | return new Subdivision(); 115 | } 116 | return this.subdivisions.get(this.subdivisions.size() - 1); 117 | } 118 | 119 | /** 120 | * @return An object representing the least specific subdivision returned. If 121 | * the response did not contain any subdivisions, this method 122 | * returns an empty {@link Subdivision} object. 123 | */ 124 | @JsonIgnore 125 | public Subdivision getLeastSpecificSubdivision() { 126 | if (this.subdivisions.isEmpty()) { 127 | return new Subdivision(); 128 | } 129 | return this.subdivisions.get(0); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/model/AbstractCountryResponse.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import com.maxmind.db.Network; 5 | import com.maxmind.geoip2.record.Continent; 6 | import com.maxmind.geoip2.record.Country; 7 | import com.maxmind.geoip2.record.MaxMind; 8 | import com.maxmind.geoip2.record.RepresentedCountry; 9 | import com.maxmind.geoip2.record.Traits; 10 | import java.util.List; 11 | 12 | /** 13 | * Abstract class for models that contain Country data. 14 | */ 15 | public abstract class AbstractCountryResponse extends AbstractResponse { 16 | 17 | private final Continent continent; 18 | private final Country country; 19 | private final Country registeredCountry; 20 | private final MaxMind maxmind; 21 | private final RepresentedCountry representedCountry; 22 | private final Traits traits; 23 | 24 | AbstractCountryResponse( 25 | Continent continent, 26 | Country country, 27 | MaxMind maxmind, 28 | Country registeredCountry, 29 | RepresentedCountry representedCountry, 30 | Traits traits 31 | ) { 32 | this.continent = continent != null ? continent : new Continent(); 33 | this.country = country != null ? country : new Country(); 34 | this.registeredCountry = registeredCountry != null ? registeredCountry : new Country(); 35 | this.maxmind = maxmind != null ? maxmind : new MaxMind(); 36 | this.representedCountry = 37 | representedCountry != null ? representedCountry : new RepresentedCountry(); 38 | this.traits = traits != null ? traits : new Traits(); 39 | } 40 | 41 | AbstractCountryResponse( 42 | AbstractCountryResponse response, 43 | String ipAddress, 44 | Network network, 45 | List locales 46 | ) { 47 | // The response fields will be non-null because of the above 48 | // constructor used during deserializing. 49 | this.continent = new Continent(response.getContinent(), locales); 50 | this.country = new Country(response.getCountry(), locales); 51 | this.maxmind = response.getMaxMind(); 52 | this.registeredCountry = new Country(response.getRegisteredCountry(), locales); 53 | this.representedCountry = new RepresentedCountry(response.getRepresentedCountry(), locales); 54 | this.traits = new Traits(response.getTraits(), ipAddress, network); 55 | } 56 | 57 | /** 58 | * @return MaxMind record containing data related to your account. 59 | */ 60 | @JsonProperty("maxmind") 61 | public MaxMind getMaxMind() { 62 | return this.maxmind; 63 | } 64 | 65 | /** 66 | * @return Registered country record for the requested IP address. This 67 | * record represents the country where the ISP has registered a 68 | * given IP block and may differ from the user's country. 69 | */ 70 | @JsonProperty("registered_country") 71 | public Country getRegisteredCountry() { 72 | return this.registeredCountry; 73 | } 74 | 75 | /** 76 | * @return Continent record for the requested IP address. 77 | */ 78 | public Continent getContinent() { 79 | return this.continent; 80 | } 81 | 82 | /** 83 | * @return Country record for the requested IP address. This object 84 | * represents the country where MaxMind believes the end user is 85 | * located. 86 | */ 87 | public Country getCountry() { 88 | return this.country; 89 | } 90 | 91 | /** 92 | * @return Represented country record for the requested IP address. The 93 | * represented country is used for things like military bases. It is 94 | * only present when the represented country differs from the 95 | * country. 96 | */ 97 | @JsonProperty("represented_country") 98 | public RepresentedCountry getRepresentedCountry() { 99 | return this.representedCountry; 100 | } 101 | 102 | /** 103 | * @return Record for the traits of the requested IP address. 104 | */ 105 | public Traits getTraits() { 106 | return this.traits; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/model/AbstractResponse.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 4 | import com.fasterxml.jackson.databind.MapperFeature; 5 | import com.fasterxml.jackson.databind.json.JsonMapper; 6 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 7 | import java.io.IOException; 8 | 9 | /** 10 | * Abstract class for GeoIP2 models. 11 | */ 12 | public abstract class AbstractResponse { 13 | 14 | /** 15 | * @return JSON representation of this object. The structure is the same as 16 | * the JSON provided by the GeoIP2 web service. 17 | * @throws IOException if there is an error serializing the object to JSON. 18 | */ 19 | public String toJson() throws IOException { 20 | JsonMapper mapper = JsonMapper.builder() 21 | .disable(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS) 22 | .addModule(new JavaTimeModule()) 23 | .serializationInclusion(Include.NON_NULL) 24 | .serializationInclusion(Include.NON_EMPTY) 25 | .build(); 26 | 27 | return mapper.writeValueAsString(this); 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | // This exception should never happen. If it does happen, we did 33 | // something wrong. 34 | try { 35 | return getClass().getName() + " [ " + toJson() + " ]"; 36 | } catch (IOException e) { 37 | throw new RuntimeException(e); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/model/AnonymousIpResponse.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import com.fasterxml.jackson.annotation.JacksonInject; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.maxmind.db.MaxMindDbConstructor; 7 | import com.maxmind.db.MaxMindDbParameter; 8 | import com.maxmind.db.Network; 9 | import com.maxmind.geoip2.NetworkDeserializer; 10 | 11 | /** 12 | * This class provides the GeoIP2 Anonymous IP model. 13 | */ 14 | public class AnonymousIpResponse extends IpBaseResponse { 15 | 16 | /** 17 | * Constructs an instance of {@code AnonymousIpResponse} with the specified values. 18 | * 19 | * @param ipAddress the IP address being checked 20 | * @param isAnonymous whether the IP address belongs to any sort of anonymous network 21 | * @param isAnonymousVpn whether the IP address belongs to an anonymous VPN system 22 | * @param isHostingProvider whether the IP address belongs to a hosting provider 23 | * @param isPublicProxy whether the IP address belongs to a public proxy system 24 | * @param isResidentialProxy whether the IP address belongs to a residential proxy system 25 | * @param isTorExitNode whether the IP address is a Tor exit node 26 | * @param network the network associated with the record 27 | */ 28 | public AnonymousIpResponse( 29 | @JacksonInject("ip_address") @JsonProperty("ip_address") String ipAddress, 30 | @JsonProperty("is_anonymous") boolean isAnonymous, 31 | @JsonProperty("is_anonymous_vpn") boolean isAnonymousVpn, 32 | @JsonProperty("is_hosting_provider") boolean isHostingProvider, 33 | @JsonProperty("is_public_proxy") boolean isPublicProxy, 34 | @JsonProperty("is_residential_proxy") boolean isResidentialProxy, 35 | @JsonProperty("is_tor_exit_node") boolean isTorExitNode, 36 | @JacksonInject("network") @JsonProperty("network") 37 | @JsonDeserialize(using = NetworkDeserializer.class) Network network 38 | ) { 39 | super(ipAddress, isAnonymous, isAnonymousVpn, isHostingProvider, isPublicProxy, 40 | isResidentialProxy, isTorExitNode, network); 41 | } 42 | 43 | /** 44 | * Constructs an instance of {@code AnonymousIpResponse} with the specified values. 45 | * 46 | * @param ipAddress the IP address being checked 47 | * @param isAnonymous whether the IP address belongs to any sort of anonymous network 48 | * @param isAnonymousVpn whether the IP address belongs to an anonymous VPN system 49 | * @param isHostingProvider whether the IP address belongs to a hosting provider 50 | * @param isPublicProxy whether the IP address belongs to a public proxy system 51 | * @param isResidentialProxy whether the IP address belongs to a residential proxy system 52 | * @param isTorExitNode whether the IP address is a Tor exit node 53 | * @param network the network associated with the record 54 | */ 55 | @MaxMindDbConstructor 56 | public AnonymousIpResponse( 57 | @MaxMindDbParameter(name = "ip_address") String ipAddress, 58 | @MaxMindDbParameter(name = "is_anonymous") Boolean isAnonymous, 59 | @MaxMindDbParameter(name = "is_anonymous_vpn") Boolean isAnonymousVpn, 60 | @MaxMindDbParameter(name = "is_hosting_provider") Boolean isHostingProvider, 61 | @MaxMindDbParameter(name = "is_public_proxy") Boolean isPublicProxy, 62 | @MaxMindDbParameter(name = "is_residential_proxy") Boolean isResidentialProxy, 63 | @MaxMindDbParameter(name = "is_tor_exit_node") Boolean isTorExitNode, 64 | @MaxMindDbParameter(name = "network") Network network 65 | ) { 66 | this( 67 | ipAddress, 68 | isAnonymous != null ? isAnonymous : false, 69 | isAnonymousVpn != null ? isAnonymousVpn : false, 70 | isHostingProvider != null ? isHostingProvider : false, 71 | isPublicProxy != null ? isPublicProxy : false, 72 | isResidentialProxy != null ? isResidentialProxy : false, 73 | isTorExitNode != null ? isTorExitNode : false, 74 | network 75 | ); 76 | } 77 | 78 | /** 79 | * Constructs an instance of {@code AnonymousIpResponse} from the values in the passed 80 | * response and the specified IP address and network. 81 | * 82 | * @param response the response to copy 83 | * @param ipAddress the IP address being checked 84 | * @param network the network associated with the record 85 | */ 86 | public AnonymousIpResponse( 87 | AnonymousIpResponse response, 88 | String ipAddress, 89 | Network network 90 | ) { 91 | this( 92 | ipAddress, 93 | response.isAnonymous(), 94 | response.isAnonymousVpn(), 95 | response.isHostingProvider(), 96 | response.isPublicProxy(), 97 | response.isResidentialProxy(), 98 | response.isTorExitNode(), 99 | network 100 | ); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/model/AnonymousPlusResponse.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import com.fasterxml.jackson.annotation.JacksonInject; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.maxmind.db.MaxMindDbConstructor; 7 | import com.maxmind.db.MaxMindDbParameter; 8 | import com.maxmind.db.Network; 9 | import com.maxmind.geoip2.NetworkDeserializer; 10 | import java.time.LocalDate; 11 | 12 | /** 13 | * This class provides the GeoIP Anonymous Plus model. 14 | */ 15 | public class AnonymousPlusResponse extends AnonymousIpResponse { 16 | private final Integer anonymizerConfidence; 17 | private final LocalDate networkLastSeen; 18 | private final String providerName; 19 | 20 | /** 21 | * Constructs an instance of {@code AnonymousPlusResponse} with the specified values. 22 | * 23 | * @param anonymizerConfidence confidence that the network is a VPN. 24 | * @param ipAddress the IP address being checked 25 | * @param isAnonymous whether the IP address belongs to any sort of anonymous network 26 | * @param isAnonymousVpn whether the IP address belongs to an anonymous VPN system 27 | * @param isHostingProvider whether the IP address belongs to a hosting provider 28 | * @param isPublicProxy whether the IP address belongs to a public proxy system 29 | * @param isResidentialProxy whether the IP address belongs to a residential proxy system 30 | * @param isTorExitNode whether the IP address is a Tor exit node 31 | * @param network the network associated with the record 32 | * @param networkLastSeen the last sighting of the network. 33 | * @param providerName the name of the VPN provider. 34 | */ 35 | public AnonymousPlusResponse( 36 | @JsonProperty("anonymizer_confidence") Integer anonymizerConfidence, 37 | @JacksonInject("ip_address") @JsonProperty("ip_address") String ipAddress, 38 | @JsonProperty("is_anonymous") Boolean isAnonymous, 39 | @JsonProperty("is_anonymous_vpn") Boolean isAnonymousVpn, 40 | @JsonProperty("is_hosting_provider") Boolean isHostingProvider, 41 | @JsonProperty("is_public_proxy") Boolean isPublicProxy, 42 | @JsonProperty("is_residential_proxy") Boolean isResidentialProxy, 43 | @JsonProperty("is_tor_exit_node") Boolean isTorExitNode, 44 | @JacksonInject("network") @JsonDeserialize(using = NetworkDeserializer.class) 45 | @JsonProperty("network") Network network, 46 | @JsonProperty("network_last_seen") LocalDate networkLastSeen, 47 | @JsonProperty("provider_name") String providerName 48 | ) { 49 | super(ipAddress, isAnonymous, isAnonymousVpn, isHostingProvider, isPublicProxy, 50 | isResidentialProxy, isTorExitNode, network); 51 | 52 | this.anonymizerConfidence = anonymizerConfidence; 53 | this.networkLastSeen = networkLastSeen; 54 | this.providerName = providerName; 55 | } 56 | 57 | /** 58 | * Constructs an instance of {@code AnonymousPlusResponse} with the specified values. 59 | * 60 | * @param anonymizerConfidence confidence that the network is a VPN. 61 | * @param ipAddress the IP address being checked 62 | * @param isAnonymous whether the IP address belongs to any sort of anonymous network 63 | * @param isAnonymousVpn whether the IP address belongs to an anonymous VPN system 64 | * @param isHostingProvider whether the IP address belongs to a hosting provider 65 | * @param isPublicProxy whether the IP address belongs to a public proxy system 66 | * @param isResidentialProxy whether the IP address belongs to a residential proxy system 67 | * @param isTorExitNode whether the IP address is a Tor exit node 68 | * @param network the network associated with the record 69 | * @param networkLastSeen the last sighting of the network. 70 | * @param providerName the name of the VPN provider. 71 | */ 72 | @MaxMindDbConstructor 73 | public AnonymousPlusResponse( 74 | @MaxMindDbParameter(name = "anonymizer_confidence") Integer anonymizerConfidence, 75 | @MaxMindDbParameter(name = "ip_address") String ipAddress, 76 | @MaxMindDbParameter(name = "is_anonymous") Boolean isAnonymous, 77 | @MaxMindDbParameter(name = "is_anonymous_vpn") Boolean isAnonymousVpn, 78 | @MaxMindDbParameter(name = "is_hosting_provider") Boolean isHostingProvider, 79 | @MaxMindDbParameter(name = "is_public_proxy") Boolean isPublicProxy, 80 | @MaxMindDbParameter(name = "is_residential_proxy") Boolean isResidentialProxy, 81 | @MaxMindDbParameter(name = "is_tor_exit_node") Boolean isTorExitNode, 82 | @MaxMindDbParameter(name = "network") Network network, 83 | @MaxMindDbParameter(name = "network_last_seen") String networkLastSeen, 84 | @MaxMindDbParameter(name = "provider_name") String providerName 85 | ) { 86 | this(anonymizerConfidence, ipAddress, isAnonymous, isAnonymousVpn, 87 | isHostingProvider, isPublicProxy, isResidentialProxy, isTorExitNode, network, 88 | networkLastSeen != null ? LocalDate.parse(networkLastSeen) : null, 89 | providerName); 90 | } 91 | 92 | /** 93 | * Constructs an instance of {@code AnonymousPlusResponse} from the values in the 94 | * response and the specified IP address and network. 95 | * 96 | * @param response the response to copy 97 | * @param ipAddress the IP address being checked 98 | * @param network the network associated with the record 99 | */ 100 | public AnonymousPlusResponse( 101 | AnonymousPlusResponse response, 102 | String ipAddress, 103 | Network network 104 | ) { 105 | this( 106 | response.getAnonymizerConfidence(), 107 | ipAddress, 108 | response.isAnonymous(), 109 | response.isAnonymousVpn(), 110 | response.isHostingProvider(), 111 | response.isPublicProxy(), 112 | response.isResidentialProxy(), 113 | response.isTorExitNode(), 114 | network, 115 | response.getNetworkLastSeen(), 116 | response.getProviderName() 117 | ); 118 | } 119 | 120 | /** 121 | * @return A score ranging from 1 to 99 that is our percent confidence that the network is 122 | * currently part of an actively used VPN service. 123 | */ 124 | @JsonProperty 125 | public Integer getAnonymizerConfidence() { 126 | return anonymizerConfidence; 127 | } 128 | 129 | /** 130 | * @return The last day that the network was sighted in our analysis of anonymized networks. 131 | */ 132 | @JsonProperty 133 | public LocalDate getNetworkLastSeen() { 134 | return networkLastSeen; 135 | } 136 | 137 | /** 138 | * @return The name of the VPN provider (e.g., NordVPN, SurfShark, etc.) associated with the 139 | * network. 140 | */ 141 | @JsonProperty 142 | public String getProviderName() { 143 | return providerName; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/model/AsnResponse.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import com.fasterxml.jackson.annotation.JacksonInject; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 7 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; 8 | import com.maxmind.db.MaxMindDbConstructor; 9 | import com.maxmind.db.MaxMindDbParameter; 10 | import com.maxmind.db.Network; 11 | import com.maxmind.geoip2.NetworkDeserializer; 12 | 13 | /** 14 | * This class provides the GeoLite2 ASN model. 15 | */ 16 | public class AsnResponse extends AbstractResponse { 17 | 18 | private final Long autonomousSystemNumber; 19 | private final String autonomousSystemOrganization; 20 | private final String ipAddress; 21 | private final Network network; 22 | 23 | /** 24 | * Constructs an instance of {@code AsnResponse} with the specified values for all fields. 25 | * 26 | * @param autonomousSystemNumber the autonomous system number associated with the IP 27 | * address 28 | * @param autonomousSystemOrganization the organization associated with the registered 29 | * autonomous system number for the IP address 30 | * @param ipAddress the IP address that the data in the model is for 31 | * @param network the network associated with the record 32 | */ 33 | @MaxMindDbConstructor 34 | public AsnResponse( 35 | @JsonProperty("autonomous_system_number") 36 | @MaxMindDbParameter(name = "autonomous_system_number") Long autonomousSystemNumber, 37 | @JsonProperty("autonomous_system_organization") 38 | @MaxMindDbParameter(name = "autonomous_system_organization") 39 | String autonomousSystemOrganization, 40 | @JacksonInject("ip_address") @JsonProperty("ip_address") 41 | @MaxMindDbParameter(name = "ip_address") String ipAddress, 42 | @JacksonInject("network") @JsonProperty("network") 43 | @JsonDeserialize(using = NetworkDeserializer.class) @MaxMindDbParameter(name = "network") 44 | Network network 45 | ) { 46 | this.autonomousSystemNumber = autonomousSystemNumber; 47 | this.autonomousSystemOrganization = autonomousSystemOrganization; 48 | this.ipAddress = ipAddress; 49 | this.network = network; 50 | } 51 | 52 | /** 53 | * Constructs an instance of {@code AsnResponse} with only the specified values set. 54 | * 55 | * @param response The {@code AsnResponse} object to copy. 56 | * @param ipAddress The IP address that the data in the model is for. 57 | * @param network The network associated with the record. 58 | */ 59 | public AsnResponse( 60 | AsnResponse response, 61 | String ipAddress, 62 | Network network 63 | ) { 64 | this( 65 | response.getAutonomousSystemNumber(), 66 | response.getAutonomousSystemOrganization(), 67 | ipAddress, 68 | network 69 | ); 70 | } 71 | 72 | /** 73 | * @return The autonomous system number associated with the IP address. 74 | */ 75 | @JsonProperty("autonomous_system_number") 76 | public Long getAutonomousSystemNumber() { 77 | return this.autonomousSystemNumber; 78 | } 79 | 80 | /** 81 | * @return The organization associated with the registered autonomous system 82 | * number for the IP address 83 | */ 84 | @JsonProperty("autonomous_system_organization") 85 | public String getAutonomousSystemOrganization() { 86 | return this.autonomousSystemOrganization; 87 | } 88 | 89 | /** 90 | * @return The IP address that the data in the model is for. 91 | */ 92 | @JsonProperty("ip_address") 93 | public String getIpAddress() { 94 | return this.ipAddress; 95 | } 96 | 97 | /** 98 | * @return The network associated with the record. In particular, this is 99 | * the largest network where all the fields besides IP address have the 100 | * same value. 101 | */ 102 | @JsonProperty 103 | @JsonSerialize(using = ToStringSerializer.class) 104 | public Network getNetwork() { 105 | return this.network; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/model/CityResponse.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import com.fasterxml.jackson.annotation.JacksonInject; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.maxmind.db.MaxMindDbConstructor; 6 | import com.maxmind.db.MaxMindDbParameter; 7 | import com.maxmind.db.Network; 8 | import com.maxmind.geoip2.record.City; 9 | import com.maxmind.geoip2.record.Continent; 10 | import com.maxmind.geoip2.record.Country; 11 | import com.maxmind.geoip2.record.Location; 12 | import com.maxmind.geoip2.record.MaxMind; 13 | import com.maxmind.geoip2.record.Postal; 14 | import com.maxmind.geoip2.record.RepresentedCountry; 15 | import com.maxmind.geoip2.record.Subdivision; 16 | import com.maxmind.geoip2.record.Traits; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | /** 21 | * This class provides a model for the data returned by the City Plus web 22 | * service and the City database. 23 | * 24 | * @see GeoIP2 Web 25 | * Services 26 | */ 27 | public final class CityResponse extends AbstractCityResponse { 28 | /** 29 | * Constructs an instance of {@code CityResponse} with the specified parameters. 30 | * 31 | * @param city city 32 | * @param continent continent 33 | * @param country country 34 | * @param location location 35 | * @param maxmind maxmind record for the response 36 | * @param postal postal 37 | * @param registeredCountry registered country 38 | * @param representedCountry represented country 39 | * @param subdivisions subdivisions 40 | * @param traits traits 41 | */ 42 | @MaxMindDbConstructor 43 | public CityResponse( 44 | @JsonProperty("city") @MaxMindDbParameter(name = "city") City city, 45 | @JsonProperty("continent") @MaxMindDbParameter(name = "continent") Continent continent, 46 | @JsonProperty("country") @MaxMindDbParameter(name = "country") Country country, 47 | @JsonProperty("location") @MaxMindDbParameter(name = "location") Location location, 48 | @JsonProperty("maxmind") @MaxMindDbParameter(name = "maxmind") MaxMind maxmind, 49 | @JsonProperty("postal") @MaxMindDbParameter(name = "postal") Postal postal, 50 | @JsonProperty("registered_country") @MaxMindDbParameter(name = "registered_country") 51 | Country registeredCountry, 52 | @JsonProperty("represented_country") @MaxMindDbParameter(name = "represented_country") 53 | RepresentedCountry representedCountry, 54 | @JsonProperty("subdivisions") @MaxMindDbParameter(name = "subdivisions") 55 | ArrayList subdivisions, 56 | @JacksonInject("traits") @JsonProperty("traits") @MaxMindDbParameter(name = "traits") 57 | Traits traits 58 | ) { 59 | super(city, continent, country, location, maxmind, postal, registeredCountry, 60 | representedCountry, subdivisions, traits); 61 | } 62 | 63 | /** 64 | * Constructs an instance of {@code CityResponse} with the specified parameters. 65 | * 66 | * @param response the response 67 | * @param ipAddress the IP address that the data in the model is for. 68 | * @param network the network associated with the record. 69 | * @param locales the locales 70 | */ 71 | public CityResponse( 72 | CityResponse response, 73 | String ipAddress, 74 | Network network, 75 | List locales 76 | ) { 77 | super(response, ipAddress, network, locales); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/model/ConnectionTypeResponse.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import com.fasterxml.jackson.annotation.JacksonInject; 4 | import com.fasterxml.jackson.annotation.JsonCreator; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import com.fasterxml.jackson.annotation.JsonValue; 7 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 8 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 9 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; 10 | import com.maxmind.db.MaxMindDbConstructor; 11 | import com.maxmind.db.MaxMindDbParameter; 12 | import com.maxmind.db.Network; 13 | import com.maxmind.geoip2.NetworkDeserializer; 14 | 15 | /** 16 | * This class provides the GeoIP2 Connection-Type model. 17 | */ 18 | public class ConnectionTypeResponse extends AbstractResponse { 19 | 20 | /** 21 | * The enumerated values that connection-type may take. 22 | */ 23 | public enum ConnectionType { 24 | DIALUP("Dialup"), 25 | CABLE_DSL("Cable/DSL"), 26 | CORPORATE("Corporate"), 27 | CELLULAR("Cellular"), 28 | SATELLITE("Satellite"); 29 | 30 | private final String name; 31 | 32 | ConnectionType(String name) { 33 | this.name = name; 34 | } 35 | 36 | /* 37 | * (non-Javadoc) 38 | * 39 | * @see java.lang.Enum#toString() 40 | */ 41 | @JsonValue 42 | @Override 43 | public String toString() { 44 | return this.name; 45 | } 46 | 47 | /** 48 | * Creates an instance of {@code ConnectionTypeResponse} from a string. 49 | * 50 | * @param s The string to create the instance from. 51 | */ 52 | @JsonCreator 53 | public static ConnectionType fromString(String s) { 54 | if (s == null) { 55 | return null; 56 | } 57 | 58 | switch (s) { 59 | case "Dialup": 60 | return ConnectionType.DIALUP; 61 | case "Cable/DSL": 62 | return ConnectionType.CABLE_DSL; 63 | case "Corporate": 64 | return ConnectionType.CORPORATE; 65 | case "Cellular": 66 | return ConnectionType.CELLULAR; 67 | case "Satellite": 68 | return ConnectionType.SATELLITE; 69 | default: 70 | return null; 71 | } 72 | } 73 | } 74 | 75 | private final ConnectionType connectionType; 76 | private final String ipAddress; 77 | private final Network network; 78 | 79 | /** 80 | * Constructs an instance of {@code ConnectionTypeResponse}. 81 | * 82 | * @param connectionType The connection type of the IP address. 83 | * @param ipAddress The IP address that the data in the model is for. 84 | * @param network The network associated with the record. 85 | */ 86 | public ConnectionTypeResponse( 87 | @JsonProperty("connection_type") ConnectionType connectionType, 88 | @JacksonInject("ip_address") @JsonProperty("ip_address") String ipAddress, 89 | @JacksonInject("network") @JsonProperty("network") 90 | @JsonDeserialize(using = NetworkDeserializer.class) Network network 91 | ) { 92 | this.connectionType = connectionType; 93 | this.ipAddress = ipAddress; 94 | this.network = network; 95 | } 96 | 97 | /** 98 | * Constructs an instance of {@code ConnectionTypeResponse}. 99 | * 100 | * @param connectionType The connection type of the IP address. 101 | * @param ipAddress The IP address that the data in the model is for. 102 | * @param network The network associated with the record. 103 | */ 104 | @MaxMindDbConstructor 105 | public ConnectionTypeResponse( 106 | @MaxMindDbParameter(name = "connection_type") String connectionType, 107 | @MaxMindDbParameter(name = "ip_address") String ipAddress, 108 | @MaxMindDbParameter(name = "network") Network network 109 | ) { 110 | this( 111 | ConnectionType.fromString(connectionType), 112 | ipAddress, 113 | network 114 | ); 115 | } 116 | 117 | /** 118 | * Constructs an instance of {@code ConnectionTypeResponse}. 119 | * 120 | * @param response The {@code ConnectionTypeResponse} object to copy. 121 | * @param ipAddress The IP address that the data in the model is for. 122 | * @param network The network associated with the record. 123 | */ 124 | public ConnectionTypeResponse( 125 | ConnectionTypeResponse response, 126 | String ipAddress, 127 | Network network 128 | ) { 129 | this( 130 | response.getConnectionType(), 131 | ipAddress, 132 | network 133 | ); 134 | } 135 | 136 | /** 137 | * @return The connection type of the IP address. 138 | */ 139 | @JsonProperty("connection_type") 140 | public ConnectionType getConnectionType() { 141 | return this.connectionType; 142 | } 143 | 144 | /** 145 | * @return The IP address that the data in the model is for. 146 | */ 147 | @JsonProperty("ip_address") 148 | public String getIpAddress() { 149 | return this.ipAddress; 150 | } 151 | 152 | /** 153 | * @return The network associated with the record. In particular, this is 154 | * the largest network where all the fields besides IP address have the 155 | * same value. 156 | */ 157 | @JsonProperty 158 | @JsonSerialize(using = ToStringSerializer.class) 159 | public Network getNetwork() { 160 | return this.network; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/model/CountryResponse.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import com.fasterxml.jackson.annotation.JacksonInject; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.maxmind.db.MaxMindDbConstructor; 6 | import com.maxmind.db.MaxMindDbParameter; 7 | import com.maxmind.db.Network; 8 | import com.maxmind.geoip2.record.Continent; 9 | import com.maxmind.geoip2.record.Country; 10 | import com.maxmind.geoip2.record.MaxMind; 11 | import com.maxmind.geoip2.record.RepresentedCountry; 12 | import com.maxmind.geoip2.record.Traits; 13 | import java.util.List; 14 | 15 | /** 16 | * This class provides a model for the data returned by the Country web service 17 | * and the Country database. 18 | * 19 | * @see GeoIP2 Web 20 | * Services 21 | */ 22 | public final class CountryResponse extends AbstractCountryResponse { 23 | 24 | /** 25 | * Constructs an instance of {@code CountryResponse} with the specified parameters. 26 | * 27 | * @param continent the continent 28 | * @param country the country 29 | * @param maxmind the MaxMind record 30 | * @param registeredCountry the registered country 31 | * @param representedCountry the represented country 32 | * @param traits the traits 33 | */ 34 | @MaxMindDbConstructor 35 | public CountryResponse( 36 | @JsonProperty("continent") @MaxMindDbParameter(name = "continent") Continent continent, 37 | @JsonProperty("country") @MaxMindDbParameter(name = "country") Country country, 38 | @JsonProperty("maxmind") @MaxMindDbParameter(name = "maxmind") MaxMind maxmind, 39 | @JsonProperty("registered_country") @MaxMindDbParameter(name = "registered_country") 40 | Country registeredCountry, 41 | @JsonProperty("represented_country") @MaxMindDbParameter(name = "represented_country") 42 | RepresentedCountry representedCountry, 43 | @JacksonInject("traits") @JsonProperty("traits") @MaxMindDbParameter(name = "traits") 44 | Traits traits 45 | ) { 46 | super(continent, country, maxmind, registeredCountry, representedCountry, traits); 47 | } 48 | 49 | /** 50 | * Constructs an instance of {@code CountryResponse} with the specified parameters. 51 | * 52 | * @param response the response 53 | * @param ipAddress the IP address that the data in the model is for. 54 | * @param network the network associated with the record. 55 | * @param locales the locales 56 | */ 57 | public CountryResponse( 58 | CountryResponse response, 59 | String ipAddress, 60 | Network network, 61 | List locales 62 | ) { 63 | super(response, ipAddress, network, locales); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/model/DomainResponse.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import com.fasterxml.jackson.annotation.JacksonInject; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 7 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; 8 | import com.maxmind.db.MaxMindDbConstructor; 9 | import com.maxmind.db.MaxMindDbParameter; 10 | import com.maxmind.db.Network; 11 | import com.maxmind.geoip2.NetworkDeserializer; 12 | 13 | /** 14 | * This class provides the GeoIP2 Domain model. 15 | */ 16 | public class DomainResponse extends AbstractResponse { 17 | 18 | private final String domain; 19 | private final String ipAddress; 20 | private final Network network; 21 | 22 | /** 23 | * Constructs an instance of {@code DomainResponse}. 24 | * 25 | * @param domain the second level domain associated with the IP address 26 | * @param ipAddress the IP address that the data in the model is for 27 | * @param network the network associated with the record 28 | */ 29 | @MaxMindDbConstructor 30 | public DomainResponse( 31 | @JsonProperty("domain") @MaxMindDbParameter(name = "domain") String domain, 32 | @JacksonInject("ip_address") @JsonProperty("ip_address") 33 | @MaxMindDbParameter(name = "ip_address") String ipAddress, 34 | @JacksonInject("network") @JsonProperty("network") 35 | @JsonDeserialize(using = NetworkDeserializer.class) @MaxMindDbParameter(name = "network") 36 | Network network 37 | ) { 38 | this.domain = domain; 39 | this.ipAddress = ipAddress; 40 | this.network = network; 41 | } 42 | 43 | /** 44 | * Constructs an instance of {@code DomainResponse} with only required parameters. 45 | * 46 | * @param response the response 47 | * @param ipAddress the IP address that the data in the model is for. 48 | * @param network the network associated with the record. 49 | */ 50 | public DomainResponse( 51 | DomainResponse response, 52 | String ipAddress, 53 | Network network 54 | ) { 55 | this(response.getDomain(), ipAddress, network); 56 | } 57 | 58 | /** 59 | * @return The second level domain associated with the IP address. This 60 | * will be something like "example.com" or "example.co.uk", not 61 | * "foo.example.com". 62 | */ 63 | public String getDomain() { 64 | return this.domain; 65 | } 66 | 67 | /** 68 | * @return The IP address that the data in the model is for. 69 | */ 70 | @JsonProperty("ip_address") 71 | public String getIpAddress() { 72 | return this.ipAddress; 73 | } 74 | 75 | /** 76 | * @return The network associated with the record. In particular, this is 77 | * the largest network where all the fields besides IP address have the 78 | * same value. 79 | */ 80 | @JsonProperty 81 | @JsonSerialize(using = ToStringSerializer.class) 82 | public Network getNetwork() { 83 | return this.network; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/model/EnterpriseResponse.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import com.fasterxml.jackson.annotation.JacksonInject; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.maxmind.db.MaxMindDbConstructor; 6 | import com.maxmind.db.MaxMindDbParameter; 7 | import com.maxmind.db.Network; 8 | import com.maxmind.geoip2.record.City; 9 | import com.maxmind.geoip2.record.Continent; 10 | import com.maxmind.geoip2.record.Country; 11 | import com.maxmind.geoip2.record.Location; 12 | import com.maxmind.geoip2.record.MaxMind; 13 | import com.maxmind.geoip2.record.Postal; 14 | import com.maxmind.geoip2.record.RepresentedCountry; 15 | import com.maxmind.geoip2.record.Subdivision; 16 | import com.maxmind.geoip2.record.Traits; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | /** 21 | *

22 | * This class provides a model for the data returned by the GeoIP2 Enterprise 23 | * database 24 | *

25 | */ 26 | public final class EnterpriseResponse extends AbstractCityResponse { 27 | 28 | /** 29 | * Constructs an instance of {@code EnterpriseResponse} with the specified parameters. 30 | * 31 | * @param city city 32 | * @param continent continent 33 | * @param country country 34 | * @param location location 35 | * @param maxmind maxmind record for the response 36 | * @param postal postal 37 | * @param registeredCountry registered country 38 | * @param representedCountry represented country 39 | * @param subdivisions subdivisions 40 | * @param traits traits 41 | */ 42 | @MaxMindDbConstructor 43 | public EnterpriseResponse( 44 | @JsonProperty("city") @MaxMindDbParameter(name = "city") City city, 45 | @JsonProperty("continent") @MaxMindDbParameter(name = "continent") Continent continent, 46 | @JsonProperty("country") @MaxMindDbParameter(name = "country") Country country, 47 | @JsonProperty("location") @MaxMindDbParameter(name = "location") Location location, 48 | @JsonProperty("maxmind") @MaxMindDbParameter(name = "maxmind") MaxMind maxmind, 49 | @JsonProperty("postal") @MaxMindDbParameter(name = "postal") Postal postal, 50 | @JsonProperty("registered_country") @MaxMindDbParameter(name = "registered_country") 51 | Country registeredCountry, 52 | @JsonProperty("represented_country") @MaxMindDbParameter(name = "represented_country") 53 | RepresentedCountry representedCountry, 54 | @JsonProperty("subdivisions") @MaxMindDbParameter(name = "subdivisions") 55 | ArrayList subdivisions, 56 | @JacksonInject("traits") @JsonProperty("traits") @MaxMindDbParameter(name = "traits") 57 | Traits traits 58 | ) { 59 | super(city, continent, country, location, maxmind, postal, registeredCountry, 60 | representedCountry, subdivisions, traits); 61 | } 62 | 63 | /** 64 | * Constructs an instance of {@code EnterpriseResponse} with only required parameters. 65 | * 66 | * @param response the response 67 | * @param ipAddress the IP address that the data in the model is for. 68 | * @param network the network associated with the record. 69 | * @param locales the locales 70 | */ 71 | public EnterpriseResponse( 72 | EnterpriseResponse response, 73 | String ipAddress, 74 | Network network, 75 | List locales 76 | ) { 77 | super(response, ipAddress, network, locales); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/model/InsightsResponse.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import com.fasterxml.jackson.annotation.JacksonInject; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.maxmind.geoip2.record.City; 6 | import com.maxmind.geoip2.record.Continent; 7 | import com.maxmind.geoip2.record.Country; 8 | import com.maxmind.geoip2.record.Location; 9 | import com.maxmind.geoip2.record.MaxMind; 10 | import com.maxmind.geoip2.record.Postal; 11 | import com.maxmind.geoip2.record.RepresentedCountry; 12 | import com.maxmind.geoip2.record.Subdivision; 13 | import com.maxmind.geoip2.record.Traits; 14 | import java.util.List; 15 | 16 | /** 17 | * This class provides a model for the data returned by the Insights web 18 | * service. 19 | * 20 | * @see GeoIP2 Web 21 | * Services 22 | */ 23 | public class InsightsResponse extends AbstractCityResponse { 24 | /** 25 | * Constructs an instance of {@code InsightsResponse} with the specified parameters. 26 | * 27 | * @param city city 28 | * @param continent continent 29 | * @param country country 30 | * @param location location 31 | * @param maxmind maxmind record for the response 32 | * @param postal postal 33 | * @param registeredCountry registered country 34 | * @param representedCountry represented country 35 | * @param subdivisions subdivisions 36 | * @param traits traits 37 | */ 38 | public InsightsResponse( 39 | @JsonProperty("city") City city, 40 | @JsonProperty("continent") Continent continent, 41 | @JsonProperty("country") Country country, 42 | @JsonProperty("location") Location location, 43 | @JsonProperty("maxmind") MaxMind maxmind, 44 | @JsonProperty("postal") Postal postal, 45 | @JsonProperty("registered_country") Country registeredCountry, 46 | @JsonProperty("represented_country") RepresentedCountry representedCountry, 47 | @JsonProperty("subdivisions") List subdivisions, 48 | @JacksonInject("traits") @JsonProperty("traits") Traits traits 49 | ) { 50 | super(city, continent, country, location, maxmind, postal, registeredCountry, 51 | representedCountry, subdivisions, traits); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/model/IpBaseResponse.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 5 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; 6 | import com.maxmind.db.Network; 7 | 8 | /** 9 | * This class provides the base IP model. 10 | */ 11 | public class IpBaseResponse extends AbstractResponse { 12 | 13 | private final boolean isAnonymous; 14 | private final boolean isAnonymousVpn; 15 | private final boolean isHostingProvider; 16 | private final boolean isPublicProxy; 17 | private final boolean isResidentialProxy; 18 | private final boolean isTorExitNode; 19 | private final String ipAddress; 20 | private final Network network; 21 | 22 | /** 23 | * Constructs an instance of {@code IpBaseResponse}. 24 | * 25 | * @param ipAddress the IP address that the data in the model is for 26 | * @param isAnonymous whether the IP address belongs to any sort of anonymous network 27 | * @param isAnonymousVpn whether the IP address belongs to an anonymous VPN system 28 | * @param isHostingProvider whether the IP address belongs to a hosting provider 29 | * @param isPublicProxy whether the IP address belongs to a public proxy system 30 | * @param isResidentialProxy whether the IP address belongs to a residential proxy system 31 | * @param isTorExitNode whether the IP address is a Tor exit node 32 | * @param network the network associated with the record 33 | */ 34 | public IpBaseResponse( 35 | String ipAddress, 36 | boolean isAnonymous, 37 | boolean isAnonymousVpn, 38 | boolean isHostingProvider, 39 | boolean isPublicProxy, 40 | boolean isResidentialProxy, 41 | boolean isTorExitNode, 42 | Network network 43 | ) { 44 | this.isAnonymous = isAnonymous; 45 | this.isAnonymousVpn = isAnonymousVpn; 46 | this.isHostingProvider = isHostingProvider; 47 | this.isPublicProxy = isPublicProxy; 48 | this.isResidentialProxy = isResidentialProxy; 49 | this.isTorExitNode = isTorExitNode; 50 | this.ipAddress = ipAddress; 51 | this.network = network; 52 | } 53 | 54 | /** 55 | * @return whether the IP address belongs to any sort of anonymous network. 56 | */ 57 | @JsonProperty("is_anonymous") 58 | public boolean isAnonymous() { 59 | return isAnonymous; 60 | } 61 | 62 | /** 63 | * @return whether the IP address is registered to an anonymous VPN 64 | * provider. If a VPN provider does not register subnets under names 65 | * associated with them, we will likely only flag their IP ranges using 66 | * isHostingProvider. 67 | */ 68 | @JsonProperty("is_anonymous_vpn") 69 | public boolean isAnonymousVpn() { 70 | return isAnonymousVpn; 71 | } 72 | 73 | /** 74 | * @return whether the IP address belongs to a hosting or VPN provider 75 | * (see description of isAnonymousVpn). 76 | */ 77 | @JsonProperty("is_hosting_provider") 78 | public boolean isHostingProvider() { 79 | return isHostingProvider; 80 | } 81 | 82 | /** 83 | * @return whether the IP address belongs to a public proxy. 84 | */ 85 | @JsonProperty("is_public_proxy") 86 | public boolean isPublicProxy() { 87 | return isPublicProxy; 88 | } 89 | 90 | /** 91 | * @return whether the IP address is on a suspected anonymizing network and 92 | * belongs to a residential ISP. 93 | */ 94 | @JsonProperty("is_residential_proxy") 95 | public boolean isResidentialProxy() { 96 | return isResidentialProxy; 97 | } 98 | 99 | /** 100 | * @return whether the IP address is a Tor exit node. 101 | */ 102 | @JsonProperty("is_tor_exit_node") 103 | public boolean isTorExitNode() { 104 | return isTorExitNode; 105 | } 106 | 107 | /** 108 | * @return The IP address that the data in the model is for. 109 | */ 110 | @JsonProperty("ip_address") 111 | public String getIpAddress() { 112 | return this.ipAddress; 113 | } 114 | 115 | /** 116 | * @return The network associated with the record. In particular, this is 117 | * the largest network where all the fields besides IP address have the 118 | * same value. 119 | */ 120 | @JsonProperty 121 | @JsonSerialize(using = ToStringSerializer.class) 122 | public Network getNetwork() { 123 | return this.network; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/model/IpRiskResponse.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import com.fasterxml.jackson.annotation.JacksonInject; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.maxmind.db.MaxMindDbConstructor; 7 | import com.maxmind.db.MaxMindDbParameter; 8 | import com.maxmind.db.Network; 9 | import com.maxmind.geoip2.NetworkDeserializer; 10 | 11 | /** 12 | * This class provides the GeoIP2 IP Risk model. 13 | * 14 | * @deprecated This database has been discontinued. 15 | */ 16 | @Deprecated 17 | public class IpRiskResponse extends IpBaseResponse { 18 | 19 | private final double ipRisk; 20 | 21 | /** 22 | * Constructs an instance of {@code IpRiskResponse}. 23 | * 24 | * @param ipAddress the IP address being checked 25 | * @param isAnonymous whether the IP address belongs to any sort of anonymous network 26 | * @param isAnonymousVpn whether the IP address belongs to an anonymous VPN system 27 | * @param isHostingProvider whether the IP address belongs to a hosting provider 28 | * @param isPublicProxy whether the IP address belongs to a public proxy system 29 | * @param isResidentialProxy whether the IP address belongs to a residential proxy system 30 | * @param isTorExitNode whether the IP address is a Tor exit node 31 | * @param network the network associated with the record 32 | * @param ipRisk the IP risk of a model 33 | */ 34 | public IpRiskResponse( 35 | @JacksonInject("ip_address") @JsonProperty("ip_address") String ipAddress, 36 | @JsonProperty("is_anonymous") boolean isAnonymous, 37 | @JsonProperty("is_anonymous_vpn") boolean isAnonymousVpn, 38 | @JsonProperty("is_hosting_provider") boolean isHostingProvider, 39 | @JsonProperty("is_public_proxy") boolean isPublicProxy, 40 | @JsonProperty("is_residential_proxy") boolean isResidentialProxy, 41 | @JsonProperty("is_tor_exit_node") boolean isTorExitNode, 42 | @JacksonInject("network") @JsonProperty("network") 43 | @JsonDeserialize(using = NetworkDeserializer.class) Network network, 44 | @JsonProperty("ip_risk") double ipRisk 45 | ) { 46 | super(ipAddress, isAnonymous, isAnonymousVpn, isHostingProvider, isPublicProxy, 47 | isResidentialProxy, isTorExitNode, network); 48 | this.ipRisk = ipRisk; 49 | } 50 | 51 | /** 52 | * Constructs an instance of {@code IpRiskResponse}. 53 | * 54 | * @param ipAddress the IP address being checked 55 | * @param isAnonymous whether the IP address belongs to any sort of anonymous network 56 | * @param isAnonymousVpn whether the IP address belongs to an anonymous VPN system 57 | * @param isHostingProvider whether the IP address belongs to a hosting provider 58 | * @param isPublicProxy whether the IP address belongs to a public proxy system 59 | * @param isResidentialProxy whether the IP address belongs to a residential proxy system 60 | * @param isTorExitNode whether the IP address is a Tor exit node 61 | * @param network the network associated with the record 62 | * @param ipRisk the IP risk of a model 63 | * 64 | */ 65 | @MaxMindDbConstructor 66 | public IpRiskResponse( 67 | @MaxMindDbParameter(name = "ip_address") String ipAddress, 68 | @MaxMindDbParameter(name = "is_anonymous") Boolean isAnonymous, 69 | @MaxMindDbParameter(name = "is_anonymous_vpn") Boolean isAnonymousVpn, 70 | @MaxMindDbParameter(name = "is_hosting_provider") Boolean isHostingProvider, 71 | @MaxMindDbParameter(name = "is_public_proxy") Boolean isPublicProxy, 72 | @MaxMindDbParameter(name = "is_residential_proxy") Boolean isResidentialProxy, 73 | @MaxMindDbParameter(name = "is_tor_exit_node") Boolean isTorExitNode, 74 | @MaxMindDbParameter(name = "network") Network network, 75 | @MaxMindDbParameter(name = "ip_risk") double ipRisk 76 | 77 | ) { 78 | this( 79 | ipAddress, 80 | isAnonymous != null ? isAnonymous : false, 81 | isAnonymousVpn != null ? isAnonymousVpn : false, 82 | isHostingProvider != null ? isHostingProvider : false, 83 | isPublicProxy != null ? isPublicProxy : false, 84 | isResidentialProxy != null ? isResidentialProxy : false, 85 | isTorExitNode != null ? isTorExitNode : false, 86 | network, 87 | ipRisk 88 | 89 | ); 90 | } 91 | 92 | /** 93 | * Constructs an instance of {@code IpRiskResponse}. 94 | * 95 | * @param response The {@code IpRiskResponse} object to copy. 96 | * @param ipAddress The IP address that the data in the model is for. 97 | * @param network The network associated with the record. 98 | */ 99 | public IpRiskResponse( 100 | IpRiskResponse response, 101 | String ipAddress, 102 | Network network 103 | ) { 104 | this( 105 | ipAddress, 106 | response.isAnonymous(), 107 | response.isAnonymousVpn(), 108 | response.isHostingProvider(), 109 | response.isPublicProxy(), 110 | response.isResidentialProxy(), 111 | response.isTorExitNode(), 112 | network, 113 | response.ipRisk 114 | ); 115 | } 116 | 117 | /** 118 | * @return The IP risk of a model. 119 | */ 120 | @JsonProperty("ip_risk") 121 | public double getIpRisk() { 122 | return this.ipRisk; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/model/IspResponse.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import com.fasterxml.jackson.annotation.JacksonInject; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.maxmind.db.MaxMindDbConstructor; 7 | import com.maxmind.db.MaxMindDbParameter; 8 | import com.maxmind.db.Network; 9 | import com.maxmind.geoip2.NetworkDeserializer; 10 | 11 | /** 12 | * This class provides the GeoIP2 ISP model. 13 | */ 14 | public class IspResponse extends AsnResponse { 15 | 16 | private final String isp; 17 | private final String organization; 18 | private final String mobileCountryCode; 19 | private final String mobileNetworkCode; 20 | 21 | /** 22 | * Constructs an instance of {@code IspResponse}. 23 | * 24 | * @param autonomousSystemNumber the autonomous system number associated with the IP 25 | * address 26 | * @param autonomousSystemOrganization the organization associated with the registered 27 | * autonomous system number for the IP address 28 | * @param ipAddress the IP address that the data in the model is for 29 | * @param isp the name of the ISP associated with the IP address 30 | * @param mobileCountryCode the mobile country code (MCC) associated with the IP 31 | * @param mobileNetworkCode the mobile network code (MNC) associated with the IP 32 | * @param organization the name of the organization associated with the IP 33 | * address 34 | * @param network the network associated with the record 35 | */ 36 | @MaxMindDbConstructor 37 | public IspResponse( 38 | @JsonProperty("autonomous_system_number") 39 | @MaxMindDbParameter(name = "autonomous_system_number") Long autonomousSystemNumber, 40 | @JsonProperty("autonomous_system_organization") 41 | @MaxMindDbParameter(name = "autonomous_system_organization") 42 | String autonomousSystemOrganization, 43 | @JacksonInject("ip_address") @JsonProperty("ip_address") 44 | @MaxMindDbParameter(name = "ip_address") String ipAddress, 45 | @JsonProperty("isp") @MaxMindDbParameter(name = "isp") String isp, 46 | @JsonProperty("mobile_country_code") @MaxMindDbParameter(name = "mobile_country_code") 47 | String mobileCountryCode, 48 | @JsonProperty("mobile_network_code") @MaxMindDbParameter(name = "mobile_network_code") 49 | String mobileNetworkCode, 50 | @JsonProperty("organization") @MaxMindDbParameter(name = "organization") 51 | String organization, 52 | @JacksonInject("network") @JsonProperty("network") 53 | @JsonDeserialize(using = NetworkDeserializer.class) @MaxMindDbParameter(name = "network") 54 | Network network 55 | ) { 56 | super(autonomousSystemNumber, autonomousSystemOrganization, ipAddress, network); 57 | this.isp = isp; 58 | this.mobileCountryCode = mobileCountryCode; 59 | this.mobileNetworkCode = mobileNetworkCode; 60 | this.organization = organization; 61 | } 62 | 63 | /** 64 | * Constructs an instance of {@code IspResponse}. 65 | * 66 | * @param response The {@code AsnResponse} object to copy. 67 | * @param ipAddress The IP address that the data in the model is for. 68 | * @param network The network associated with the record. 69 | */ 70 | public IspResponse( 71 | IspResponse response, 72 | String ipAddress, 73 | Network network 74 | ) { 75 | this( 76 | response.getAutonomousSystemNumber(), 77 | response.getAutonomousSystemOrganization(), 78 | ipAddress, 79 | response.getIsp(), 80 | response.getMobileCountryCode(), 81 | response.getMobileNetworkCode(), 82 | response.getOrganization(), 83 | network 84 | ); 85 | } 86 | 87 | /** 88 | * @return The name of the ISP associated with the IP address. 89 | */ 90 | public String getIsp() { 91 | return this.isp; 92 | } 93 | 94 | /** 95 | * @return The 96 | * mobile country code (MCC) associated with the IP address and ISP. 97 | * This property is available from the City and Insights web services and 98 | * the GeoIP2 Enterprise database. 99 | */ 100 | @JsonProperty("mobile_country_code") 101 | public String getMobileCountryCode() { 102 | return this.mobileCountryCode; 103 | } 104 | 105 | /** 106 | * @return The 107 | * mobile network code (MNC) associated with the IP address and ISP. 108 | * This property is available from the City and Insights web services and 109 | * the GeoIP2 Enterprise database. 110 | */ 111 | @JsonProperty("mobile_network_code") 112 | public String getMobileNetworkCode() { 113 | return this.mobileNetworkCode; 114 | } 115 | 116 | /** 117 | * @return The name of the organization associated with the IP address. 118 | */ 119 | public String getOrganization() { 120 | return this.organization; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/record/AbstractNamedRecord.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.record; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * Abstract class for records with name maps. 12 | */ 13 | public abstract class AbstractNamedRecord extends AbstractRecord { 14 | 15 | private final Map names; 16 | private final Long geoNameId; 17 | private final List locales; 18 | 19 | AbstractNamedRecord() { 20 | this(null, null, null); 21 | } 22 | 23 | AbstractNamedRecord(List locales, Long geoNameId, Map names) { 24 | this.names = names != null ? names : new HashMap<>(); 25 | this.geoNameId = geoNameId; 26 | this.locales = locales != null ? locales : new ArrayList<>(); 27 | } 28 | 29 | /** 30 | * @return The GeoName ID for the city. 31 | */ 32 | @JsonProperty("geoname_id") 33 | public Long getGeoNameId() { 34 | return this.geoNameId; 35 | } 36 | 37 | /** 38 | * @return The name of the city based on the locales list passed to the 39 | * constructor. 40 | */ 41 | @JsonIgnore 42 | public String getName() { 43 | for (String lang : this.locales) { 44 | if (this.names.containsKey(lang)) { 45 | return this.names.get(lang); 46 | } 47 | } 48 | return null; 49 | } 50 | 51 | /** 52 | * @return A {@link Map} from locale codes to the name in that locale. 53 | */ 54 | @JsonProperty("names") 55 | public Map getNames() { 56 | return new HashMap<>(this.names); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/record/AbstractRecord.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.record; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.databind.MapperFeature; 5 | import com.fasterxml.jackson.databind.json.JsonMapper; 6 | import java.io.IOException; 7 | 8 | /** 9 | * Abstract class for GeoIP2. 10 | */ 11 | public abstract class AbstractRecord { 12 | 13 | /** 14 | * @return JSON representation of this object. The structure is the same as 15 | * the JSON provided by the GeoIP2 web service. 16 | * @throws IOException if there is an error serializing the object to JSON. 17 | */ 18 | public String toJson() throws IOException { 19 | JsonMapper mapper = JsonMapper.builder() 20 | .disable(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS) 21 | .serializationInclusion(JsonInclude.Include.NON_NULL) 22 | .serializationInclusion(JsonInclude.Include.NON_EMPTY) 23 | .build(); 24 | 25 | return mapper.writeValueAsString(this); 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | // This exception should never happen. If it does happen, we did 31 | // something wrong. 32 | try { 33 | return getClass().getName() + " [ " + toJson() + " ]"; 34 | } catch (IOException e) { 35 | throw new RuntimeException(e); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /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.MaxMindDbConstructor; 6 | import com.maxmind.db.MaxMindDbParameter; 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 #getGeoNameId} instead. 17 | *

18 | */ 19 | public final class City extends AbstractNamedRecord { 20 | 21 | private final Integer confidence; 22 | 23 | /** 24 | * Constructs an instance of {@code City} with no data. 25 | */ 26 | public City() { 27 | this(null, null, null, null); 28 | } 29 | 30 | /** 31 | * Constructs an instance of {@code City} with the specified parameters. 32 | * 33 | * @param locales The locales to use. 34 | * @param confidence A value from 0-100 indicating MaxMind's confidence that the 35 | * city is correct. . 36 | * @param geoNameId The GeoName ID for the city. 37 | * @param names A map from locale codes to the city name in that locale. 38 | */ 39 | @MaxMindDbConstructor 40 | public City( 41 | @JacksonInject("locales") @MaxMindDbParameter(name = "locales") List locales, 42 | @JsonProperty("confidence") @MaxMindDbParameter(name = "confidence") Integer confidence, 43 | @JsonProperty("geoname_id") @MaxMindDbParameter(name = "geoname_id") Long geoNameId, 44 | @JsonProperty("names") @MaxMindDbParameter(name = "names") Map names 45 | ) { 46 | super(locales, geoNameId, names); 47 | this.confidence = confidence; 48 | } 49 | 50 | /** 51 | * Constructs an instance of {@code City}. 52 | * 53 | * @param city The {@code City} object to copy. 54 | * @param locales The locales to use. 55 | */ 56 | public City( 57 | City city, 58 | List locales 59 | ) { 60 | this( 61 | locales, 62 | city.getConfidence(), 63 | city.getGeoNameId(), 64 | city.getNames() 65 | ); 66 | } 67 | 68 | /** 69 | * @return A value from 0-100 indicating MaxMind's confidence that the city 70 | * is correct. This attribute is only available from the Insights 71 | * web service and the GeoIP2 Enterprise database. 72 | */ 73 | public Integer getConfidence() { 74 | return this.confidence; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /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.MaxMindDbConstructor; 6 | import com.maxmind.db.MaxMindDbParameter; 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 #getGeoNameId} or {@link #getCode} instead. 17 | *

18 | */ 19 | public final class Continent extends AbstractNamedRecord { 20 | 21 | private final String code; 22 | 23 | /** 24 | * Constructs an instance of {@code Continent} with no data. 25 | */ 26 | public Continent() { 27 | this(null, null, null, null); 28 | } 29 | 30 | /** 31 | * Constructs an instance of {@code Continent}. 32 | * 33 | * @param locales The locales to use. 34 | * @param code A two character continent code like "NA" (North America) or 35 | * "OC" (Oceania). 36 | * @param geoNameId The GeoName ID for the continent. 37 | * @param names A map from locale codes to the continent names. 38 | */ 39 | @MaxMindDbConstructor 40 | public Continent( 41 | @JacksonInject("locales") @MaxMindDbParameter(name = "locales") List locales, 42 | @JsonProperty("code") @MaxMindDbParameter(name = "code") String code, 43 | @JsonProperty("geoname_id") @MaxMindDbParameter(name = "geoname_id") Long geoNameId, 44 | @JsonProperty("names") @MaxMindDbParameter(name = "names") Map names 45 | ) { 46 | super(locales, geoNameId, names); 47 | this.code = code; 48 | } 49 | 50 | /** 51 | * Constructs an instance of {@code Continent}. 52 | * 53 | * @param continent The {@code Continent} object to copy. 54 | * @param locales The locales to use. 55 | */ 56 | public Continent( 57 | Continent continent, 58 | List locales 59 | ) { 60 | this( 61 | locales, 62 | continent.getCode(), 63 | continent.getGeoNameId(), 64 | continent.getNames() 65 | ); 66 | } 67 | 68 | /** 69 | * @return A two character continent code like "NA" (North America) or "OC" 70 | * (Oceania). 71 | */ 72 | public String getCode() { 73 | return this.code; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /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.MaxMindDbConstructor; 6 | import com.maxmind.db.MaxMindDbParameter; 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 #getGeoNameId} or {@link #getIsoCode} instead. 17 | *

18 | */ 19 | public class Country extends AbstractNamedRecord { 20 | 21 | private final Integer confidence; 22 | private final boolean isInEuropeanUnion; 23 | private final String isoCode; 24 | 25 | /** 26 | * Constructs an instance of {@code Country} with no data. 27 | */ 28 | public Country() { 29 | this(null, null, null, false, null, null); 30 | } 31 | 32 | /** 33 | * Constructs an instance of {@code Country}. 34 | * 35 | * @param locales The locales to use. 36 | * @param confidence This is a value from 0-100 indicating MaxMind's 37 | * confidence that the country is correct. 38 | * @param geoNameId This is a GeoName ID for the country. 39 | * @param isInEuropeanUnion This is true if the country is a member state of 40 | * the European Union. 41 | * @param isoCode This is a string up to three characters long contain the 42 | * country code. 43 | * @param names This is a map from locale codes to the names for the country 44 | * in that locale. 45 | */ 46 | @MaxMindDbConstructor 47 | public Country( 48 | @JacksonInject("locales") @MaxMindDbParameter(name = "locales") List locales, 49 | @JsonProperty("confidence") @MaxMindDbParameter(name = "confidence") Integer confidence, 50 | @JsonProperty("geoname_id") @MaxMindDbParameter(name = "geoname_id") Long geoNameId, 51 | @JsonProperty("is_in_european_union") @MaxMindDbParameter(name = "is_in_european_union") 52 | Boolean isInEuropeanUnion, 53 | @JsonProperty("iso_code") @MaxMindDbParameter(name = "iso_code") String isoCode, 54 | @JsonProperty("names") @MaxMindDbParameter(name = "names") Map names 55 | ) { 56 | super(locales, geoNameId, names); 57 | this.confidence = confidence; 58 | this.isInEuropeanUnion = isInEuropeanUnion != null ? isInEuropeanUnion : false; 59 | this.isoCode = isoCode; 60 | } 61 | 62 | /** 63 | * Constructs an instance of {@code Country}. 64 | * 65 | * @param country The {@code Country} object to copy. 66 | * @param locales The locales to use. 67 | */ 68 | public Country( 69 | Country country, 70 | List locales 71 | ) { 72 | this( 73 | locales, 74 | country.getConfidence(), 75 | country.getGeoNameId(), 76 | country.isInEuropeanUnion(), 77 | country.getIsoCode(), 78 | country.getNames() 79 | ); 80 | } 81 | 82 | /** 83 | * @return A value from 0-100 indicating MaxMind's confidence that the 84 | * country is correct. This attribute is only available from the 85 | * Insights web service and the GeoIP2 Enterprise database. 86 | */ 87 | public Integer getConfidence() { 88 | return this.confidence; 89 | } 90 | 91 | /** 92 | * @return This is true if the country is a member state of the European 93 | * Union. 94 | */ 95 | @JsonProperty("is_in_european_union") 96 | public boolean isInEuropeanUnion() { 97 | return this.isInEuropeanUnion; 98 | } 99 | 100 | /** 101 | * @return The two-character ISO 103 | * 3166-1 alpha code for the country. 104 | */ 105 | @JsonProperty("iso_code") 106 | public String getIsoCode() { 107 | return this.isoCode; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /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.MaxMindDbConstructor; 5 | import com.maxmind.db.MaxMindDbParameter; 6 | 7 | /** 8 | *

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

11 | */ 12 | public class Location extends AbstractRecord { 13 | 14 | private final Integer accuracyRadius; 15 | private final Integer averageIncome; 16 | private final Double latitude; 17 | private final Double longitude; 18 | private final Integer metroCode; 19 | private final Integer populationDensity; 20 | private final String timeZone; 21 | 22 | /** 23 | * Constructs a {@code Location} record with {@code null} values for all the fields. 24 | */ 25 | public Location() { 26 | this(null, null, null, null, null, null, null); 27 | } 28 | 29 | /** 30 | * Constructs an instance of {@code Location}. 31 | * 32 | * @param accuracyRadius The approximate accuracy radius in kilometers 33 | * around the latitude and longitude for the IP address. This is the radius 34 | * where we have a 67% confidence that the device using the IP address 35 | * resides within the circle centered at the latitude and longitude with 36 | * the provided radius. 37 | * @param averageIncome The average income in US dollars associated with 38 | * the requested IP address. This attribute is only available from the 39 | * Insights web service. 40 | * @param latitude The approximate latitude of the location associated 41 | * with the IP address. This value is not precise and should not be used 42 | * to identify a particular address or household. 43 | * @param longitude The approximate longitude of the location associated 44 | * with the IP address. This value is not precise and should not be used 45 | * to identify a particular address or household. 46 | * @param metroCode The metro code of the location if the location is in 47 | * the US. MaxMind returns the same metro codes as the Google AdWords API. 50 | * @param populationDensity The estimated population per square kilometer 51 | * associated with the IP address. This attribute is only available from 52 | * the Insights web service. 53 | * @param timeZone The time zone associated with location, as specified by 54 | * the IANA Time Zone 55 | * Database, e.g., "America/New_York". 56 | */ 57 | @MaxMindDbConstructor 58 | public Location( 59 | @JsonProperty("accuracy_radius") @MaxMindDbParameter(name = "accuracy_radius") 60 | Integer accuracyRadius, 61 | @JsonProperty("average_income") @MaxMindDbParameter(name = "average_income") 62 | Integer averageIncome, 63 | @JsonProperty("latitude") @MaxMindDbParameter(name = "latitude") Double latitude, 64 | @JsonProperty("longitude") @MaxMindDbParameter(name = "longitude") Double longitude, 65 | @JsonProperty("metro_code") @MaxMindDbParameter(name = "metro_code") Integer metroCode, 66 | @JsonProperty("population_density") @MaxMindDbParameter(name = "population_density") 67 | Integer populationDensity, 68 | @JsonProperty("time_zone") @MaxMindDbParameter(name = "time_zone") String timeZone 69 | ) { 70 | this.accuracyRadius = accuracyRadius; 71 | this.averageIncome = averageIncome; 72 | this.latitude = latitude; 73 | this.longitude = longitude; 74 | this.metroCode = metroCode; 75 | this.populationDensity = populationDensity; 76 | this.timeZone = timeZone; 77 | } 78 | 79 | /** 80 | * @return The average income in US dollars associated with the requested 81 | * IP address. This attribute is only available from the Insights web 82 | * service. 83 | */ 84 | @JsonProperty("average_income") 85 | public Integer getAverageIncome() { 86 | return this.averageIncome; 87 | } 88 | 89 | /** 90 | * @return The estimated population per square kilometer associated with the 91 | * IP address. This attribute is only available from the Insights web 92 | * service. 93 | */ 94 | @JsonProperty("population_density") 95 | public Integer getPopulationDensity() { 96 | return this.populationDensity; 97 | } 98 | 99 | /** 100 | * @return The time zone associated with location, as specified by the IANA Time Zone 102 | * Database, e.g., "America/New_York". 103 | */ 104 | @JsonProperty("time_zone") 105 | public String getTimeZone() { 106 | return this.timeZone; 107 | } 108 | 109 | /** 110 | * @return The approximate accuracy radius in kilometers around the 111 | * latitude and longitude for the IP address. This is the radius where we 112 | * have a 67% confidence that the device using the IP address resides 113 | * within the circle centered at the latitude and longitude with the 114 | * provided radius. 115 | */ 116 | @JsonProperty("accuracy_radius") 117 | public Integer getAccuracyRadius() { 118 | return this.accuracyRadius; 119 | } 120 | 121 | /** 122 | * @return The metro code is a no-longer-maintained code for targeting 123 | * advertisements in Google. 124 | * @deprecated Code values are no longer maintained. 125 | */ 126 | @JsonProperty("metro_code") 127 | @Deprecated 128 | public Integer getMetroCode() { 129 | return this.metroCode; 130 | } 131 | 132 | /** 133 | * @return The approximate latitude of the location associated with the 134 | * IP address. This value is not precise and should not be used to 135 | * identify a particular address or household. 136 | */ 137 | public Double getLatitude() { 138 | return this.latitude; 139 | } 140 | 141 | /** 142 | * @return The approximate longitude of the location associated with the 143 | * IP address. This value is not precise and should not be used to 144 | * identify a particular address or household. 145 | */ 146 | public Double getLongitude() { 147 | return this.longitude; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/com/maxmind/geoip2/record/MaxMind.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.record; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import com.maxmind.db.MaxMindDbConstructor; 5 | import com.maxmind.db.MaxMindDbParameter; 6 | 7 | /** 8 | *

9 | * Contains data related to your MaxMind account. 10 | *

11 | */ 12 | public final class MaxMind extends AbstractRecord { 13 | 14 | private final Integer queriesRemaining; 15 | 16 | /** 17 | * Constructs a {@code MaxMind} record. 18 | */ 19 | public MaxMind() { 20 | this(null); 21 | } 22 | 23 | /** 24 | * Constructs a {@code MaxMind} record. 25 | * 26 | * @param queriesRemaining The number of remaining queries in the current web service call. 27 | * This returns {@code null} when called on a database. 28 | */ 29 | @MaxMindDbConstructor 30 | public MaxMind( 31 | @JsonProperty("queries_remaining") @MaxMindDbParameter(name = "queries_remaining") 32 | Integer queriesRemaining) { 33 | this.queriesRemaining = queriesRemaining; 34 | } 35 | 36 | /** 37 | * @return The number of remaining queried in your account for the current 38 | * web service. This returns {@code null} when called on a database. 39 | */ 40 | @JsonProperty("queries_remaining") 41 | public Integer getQueriesRemaining() { 42 | return this.queriesRemaining; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /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.MaxMindDbConstructor; 5 | import com.maxmind.db.MaxMindDbParameter; 6 | 7 | /** 8 | *

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

11 | */ 12 | public final class Postal extends AbstractRecord { 13 | 14 | private final String code; 15 | private final Integer confidence; 16 | 17 | /** 18 | * Constructs a {@code Postal} record. 19 | */ 20 | public Postal() { 21 | this(null, null); 22 | } 23 | 24 | /** 25 | * Constructs an instance of {@code Postal}. 26 | * 27 | * @param code The postal code of the location. Postal codes are not available 28 | * for all countries. In some countries, this will only contain part 29 | * of the postal code. 30 | * @param confidence A value from 0-100 indicating MaxMind's confidence that the 31 | * postal code is correct. This attribute is only available from the 32 | * Insights web service and the GeoIP2 Enterprise database. 33 | */ 34 | @MaxMindDbConstructor 35 | public Postal( 36 | @JsonProperty("code") @MaxMindDbParameter(name = "code") String code, 37 | @JsonProperty("confidence") @MaxMindDbParameter(name = "confidence") Integer confidence 38 | ) { 39 | this.code = code; 40 | this.confidence = confidence; 41 | } 42 | 43 | /** 44 | * @return The postal code of the location. Postal codes are not available 45 | * for all countries. In some countries, this will only contain part 46 | * of the postal code. 47 | */ 48 | public String getCode() { 49 | return this.code; 50 | } 51 | 52 | /** 53 | * @return A value from 0-100 indicating MaxMind's confidence that the 54 | * postal code is correct. This attribute is only available from the 55 | * Insights web service and the GeoIP2 Enterprise database. 56 | */ 57 | public Integer getConfidence() { 58 | return this.confidence; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /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.MaxMindDbConstructor; 6 | import com.maxmind.db.MaxMindDbParameter; 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 #getGeoNameId} or {@link #getIsoCode} instead. 22 | *

23 | */ 24 | public final class RepresentedCountry extends Country { 25 | 26 | private final String type; 27 | 28 | /** 29 | * Constructs an instance of {@code RepresentedCountry} with no data. 30 | */ 31 | public RepresentedCountry() { 32 | this(null, null, null, false, null, null, null); 33 | } 34 | 35 | /** 36 | * Constructs an instance of {@code RepresentedCountry}. 37 | * 38 | * @param locales The locales to use. 39 | * @param confidence This is a value from 0-100 indicating MaxMind's 40 | * confidence that the country is correct. 41 | * @param geoNameId This is a GeoName ID for the country. 42 | * @param isInEuropeanUnion This is true if the country is a member state of 43 | * the European Union. 44 | * @param isoCode This is a string up to three characters long contain the 45 | * country code. 46 | * @param names This is a map from locale codes to the names for the country 47 | * in that locale. 48 | * @param type This is a string indicating the type of entity that is 49 | * representing the country. 50 | */ 51 | @MaxMindDbConstructor 52 | public RepresentedCountry( 53 | @JacksonInject("locales") @MaxMindDbParameter(name = "locales") List locales, 54 | @JsonProperty("confidence") @MaxMindDbParameter(name = "confidence") Integer confidence, 55 | @JsonProperty("geoname_id") @MaxMindDbParameter(name = "geoname_id") Long geoNameId, 56 | @JsonProperty("is_in_european_union") @MaxMindDbParameter(name = "is_in_european_union") 57 | Boolean isInEuropeanUnion, 58 | @JsonProperty("iso_code") @MaxMindDbParameter(name = "iso_code") String isoCode, 59 | @JsonProperty("names") @MaxMindDbParameter(name = "names") Map names, 60 | @JsonProperty("type") @MaxMindDbParameter(name = "type") String type 61 | ) { 62 | super(locales, confidence, geoNameId, isInEuropeanUnion, isoCode, 63 | names); 64 | this.type = type; 65 | } 66 | 67 | /** 68 | * Constructs an instance of {@code RepresentedCountry}. 69 | * 70 | * @param country The {@code RepresentedCountry} object to copy. 71 | * @param locales The locales to use. 72 | */ 73 | public RepresentedCountry( 74 | RepresentedCountry country, 75 | List locales 76 | ) { 77 | this( 78 | locales, 79 | country.getConfidence(), 80 | country.getGeoNameId(), 81 | country.isInEuropeanUnion(), 82 | country.getIsoCode(), 83 | country.getNames(), 84 | country.getType() 85 | ); 86 | } 87 | 88 | /** 89 | * @return A string indicating the type of entity that is representing the 90 | * country. Currently, we only return {@code military} but this could 91 | * expand to include other types in the future. 92 | */ 93 | public String getType() { 94 | return this.type; 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /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.MaxMindDbConstructor; 6 | import com.maxmind.db.MaxMindDbParameter; 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 #getGeoNameId} or {@link #getIsoCode} instead. 17 | *

18 | */ 19 | public final class Subdivision extends AbstractNamedRecord { 20 | 21 | private final Integer confidence; 22 | private final String isoCode; 23 | 24 | /** 25 | * Constructs a {@code Subdivision} record. 26 | */ 27 | public Subdivision() { 28 | this(null, null, null, null, null); 29 | } 30 | 31 | /** 32 | * Constructs an instance of {@code Subdivision}. 33 | * 34 | * @param locales The locales to use. 35 | * @param confidence This is a value from 0-100 indicating MaxMind's 36 | * confidence that the subdivision is correct. 37 | * @param geoNameId This is a GeoName ID for the subdivision. 38 | * @param isoCode This is a string up to three characters long contain the subdivision code. 39 | * @param names This is a map from locale codes to the names for the subdivision in that locale. 40 | */ 41 | @MaxMindDbConstructor 42 | public Subdivision( 43 | @JacksonInject("locales") @MaxMindDbParameter(name = "locales") List locales, 44 | @JsonProperty("confidence") @MaxMindDbParameter(name = "confidence") Integer confidence, 45 | @JsonProperty("geoname_id") @MaxMindDbParameter(name = "geoname_id") Long geoNameId, 46 | @JsonProperty("iso_code") @MaxMindDbParameter(name = "iso_code") String isoCode, 47 | @JsonProperty("names") @MaxMindDbParameter(name = "names") Map names 48 | ) { 49 | super(locales, geoNameId, names); 50 | this.confidence = confidence; 51 | this.isoCode = isoCode; 52 | } 53 | 54 | /** 55 | * Constructs an instance of {@code Subdivision} with the specified parameters. 56 | * 57 | * @param subdivision The {@code Subdivision} object to copy. 58 | * @param locales The locales to use. 59 | */ 60 | public Subdivision( 61 | Subdivision subdivision, 62 | List locales 63 | ) { 64 | this( 65 | locales, 66 | subdivision.getConfidence(), 67 | subdivision.getGeoNameId(), 68 | subdivision.getIsoCode(), 69 | subdivision.getNames() 70 | ); 71 | } 72 | 73 | /** 74 | * @return This is a value from 0-100 indicating MaxMind's confidence that 75 | * the subdivision is correct. This attribute is only available from 76 | * the Insights web service and the GeoIP2 Enterprise database. 77 | */ 78 | @JsonProperty("confidence") 79 | public Integer getConfidence() { 80 | return this.confidence; 81 | } 82 | 83 | /** 84 | * @return This is a string up to three characters long contain the 85 | * subdivision portion of the ISO 87 | * 3166-2code. 88 | */ 89 | @JsonProperty("iso_code") 90 | public String getIsoCode() { 91 | return this.isoCode; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | @SuppressWarnings("module") // suppress terminal digit warning 2 | module com.maxmind.geoip2 { 3 | requires com.fasterxml.jackson.annotation; 4 | requires com.fasterxml.jackson.databind; 5 | requires com.fasterxml.jackson.datatype.jsr310; 6 | requires transitive com.maxmind.db; 7 | requires java.net.http; 8 | 9 | exports com.maxmind.geoip2; 10 | exports com.maxmind.geoip2.exception; 11 | exports com.maxmind.geoip2.model; 12 | exports com.maxmind.geoip2.record; 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/com/maxmind/geoip2/json/File.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.json; 2 | 3 | import java.io.IOException; 4 | import java.net.URISyntaxException; 5 | import java.net.URL; 6 | import java.nio.file.Files; 7 | import java.nio.file.Paths; 8 | 9 | public class File { 10 | public static String readJsonFile(String name) throws IOException, 11 | URISyntaxException { 12 | URL resource = File.class 13 | .getResource("/test-data/" + name + ".json"); 14 | return Files.readString(Paths.get(resource.toURI())); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/maxmind/geoip2/matchers/CodeMatcher.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.matchers; 2 | 3 | import com.maxmind.geoip2.exception.InvalidRequestException; 4 | import org.hamcrest.Description; 5 | import org.hamcrest.TypeSafeMatcher; 6 | 7 | public class CodeMatcher extends TypeSafeMatcher { 8 | 9 | private String foundErrorCode; 10 | private final String expectedErrorCode; 11 | 12 | public static CodeMatcher hasCode(String item) { 13 | return new CodeMatcher(item); 14 | } 15 | 16 | private CodeMatcher(String expectedErrorCode) { 17 | this.expectedErrorCode = expectedErrorCode; 18 | } 19 | 20 | @Override 21 | protected boolean matchesSafely(final InvalidRequestException exception) { 22 | this.foundErrorCode = exception.getCode(); 23 | return this.foundErrorCode.equalsIgnoreCase(this.expectedErrorCode); 24 | } 25 | 26 | @Override 27 | public void describeTo(Description description) { 28 | description.appendValue(this.foundErrorCode) 29 | .appendText(" was not found instead of ") 30 | .appendValue(this.expectedErrorCode); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/maxmind/geoip2/matchers/HttpStatusMatcher.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.matchers; 2 | 3 | import com.maxmind.geoip2.exception.HttpException; 4 | import org.hamcrest.Description; 5 | import org.hamcrest.TypeSafeMatcher; 6 | 7 | public class HttpStatusMatcher extends TypeSafeMatcher { 8 | 9 | private int foundStatusCode; 10 | private final int expectedStatusCode; 11 | 12 | public static HttpStatusMatcher hasStatus(int item) { 13 | return new HttpStatusMatcher(item); 14 | } 15 | 16 | private HttpStatusMatcher(int expectedStatusCode) { 17 | this.expectedStatusCode = expectedStatusCode; 18 | } 19 | 20 | @Override 21 | protected boolean matchesSafely(final HttpException exception) { 22 | this.foundStatusCode = exception.getHttpStatus(); 23 | return this.foundStatusCode == this.expectedStatusCode; 24 | } 25 | 26 | @Override 27 | public void describeTo(Description description) { 28 | description.appendValue(String.valueOf(this.foundStatusCode)) 29 | .appendText(" was not found instead of ") 30 | .appendValue(String.valueOf(this.expectedStatusCode)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /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.getContinent().getName(), 59 | "country.getContinent().getName() does not return 北美洲" 60 | ); 61 | assertEquals( 62 | "美国", 63 | city.getCountry().getName(), 64 | "country.getCountry().getName() does not return 美国" 65 | ); 66 | assertEquals( 67 | city.getCountry() 68 | .getName(), city.getCountry().getName(), 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.getCountry().getName(), 86 | "country.getCountry().getName() 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.getContinent().getName(), 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.getContinent().getName(), 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.getContinent().getName(), 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.getCity()); 152 | assertNull(city.getCity().getName(), "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.getContinent().getCode(), 56 | "country.getContinent().getCode() does not return NA" 57 | ); 58 | assertEquals( 59 | 42, 60 | this.country.getContinent().getGeoNameId(), 61 | "country.getContinent().getGeoNameId() does not return 42" 62 | ); 63 | assertEquals( 64 | "North America", 65 | this.country.getContinent().getName(), 66 | "country.getContinent().getName() does not return North America" 67 | ); 68 | } 69 | 70 | @Test 71 | public void testCountry() { 72 | assertFalse( 73 | this.country.getCountry().isInEuropeanUnion(), 74 | "country.getCountry().isInEuropeanUnion() does not return false" 75 | ); 76 | assertEquals( 77 | this.country.getCountry().getIsoCode(), 78 | "US", 79 | "country.getCountry().getCode() does not return US" 80 | ); 81 | assertEquals( 82 | 1, 83 | (long) this.country.getCountry().getGeoNameId(), 84 | "country.getCountry().getGeoNameId() does not return 1" 85 | ); 86 | assertEquals( 87 | Integer.valueOf(56), 88 | this.country.getCountry().getConfidence(), 89 | "country.getCountry().getConfidence() does not return 56" 90 | ); 91 | assertEquals( 92 | "United States", 93 | this.country.getCountry().getName(), 94 | "country.getCountry().getName(\"en\") does not return United States" 95 | ); 96 | } 97 | 98 | @Test 99 | public void testRegisteredCountry() { 100 | assertFalse( 101 | this.country.getRegisteredCountry().isInEuropeanUnion(), 102 | "country.getRegisteredCountry().isInEuropeanUnion() does not return false" 103 | ); 104 | assertEquals( 105 | "CA", 106 | this.country.getRegisteredCountry().getIsoCode(), 107 | "country.getRegisteredCountry().getIsoCode() does not return CA" 108 | ); 109 | assertEquals( 110 | 2, 111 | (long) this.country.getRegisteredCountry().getGeoNameId(), 112 | "country.getRegisteredCountry().getGeoNameId() does not return 2" 113 | ); 114 | assertEquals( 115 | "Canada", 116 | this.country.getRegisteredCountry().getName(), 117 | "country.getRegisteredCountry().getName(\"en\") does not return United States" 118 | ); 119 | } 120 | 121 | @Test 122 | public void testRepresentedCountry() { 123 | assertTrue( 124 | this.country.getRepresentedCountry().isInEuropeanUnion(), 125 | "country.getRepresentedCountry().isInEuropeanUnion() does not return true" 126 | ); 127 | assertEquals( 128 | "GB", 129 | this.country.getRepresentedCountry().getIsoCode(), 130 | "country.getRepresentedCountry().getCode() does not return GB" 131 | ); 132 | assertEquals( 133 | 4, 134 | (long) this.country.getRepresentedCountry().getGeoNameId(), 135 | "country.getRepresentedCountry().getGeoNameId() does not return 4" 136 | ); 137 | assertEquals( 138 | "United Kingdom", 139 | this.country.getRepresentedCountry().getName(), 140 | "country.getRepresentedCountry().getName(\"en\") does not return United Kingdom" 141 | ); 142 | assertEquals( 143 | "military", 144 | this.country.getRepresentedCountry().getType(), 145 | "country.getRepresentedCountry().getType() does not return military" 146 | ); 147 | } 148 | 149 | @Test 150 | public void testTraits() { 151 | 152 | assertEquals( 153 | "1.2.3.4", 154 | this.country.getTraits().getIpAddress(), 155 | "country.getTraits().getIpAddress does not return 1.2.3.4" 156 | ); 157 | 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /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.Location; 19 | import com.maxmind.geoip2.record.MaxMind; 20 | import com.maxmind.geoip2.record.Postal; 21 | import com.maxmind.geoip2.record.Subdivision; 22 | import com.maxmind.geoip2.record.Traits; 23 | import java.io.IOException; 24 | import java.net.InetAddress; 25 | import java.net.URISyntaxException; 26 | import java.util.List; 27 | import org.junit.jupiter.api.BeforeEach; 28 | import org.junit.jupiter.api.Test; 29 | import org.junit.jupiter.api.extension.RegisterExtension; 30 | 31 | @WireMockTest 32 | public class InsightsResponseTest { 33 | @RegisterExtension 34 | static WireMockExtension wireMock = WireMockExtension.newInstance() 35 | .options(wireMockConfig().dynamicPort().dynamicHttpsPort()) 36 | .build(); 37 | 38 | private InsightsResponse insights; 39 | 40 | @BeforeEach 41 | public void createClient() throws IOException, GeoIp2Exception, 42 | URISyntaxException { 43 | wireMock.stubFor(get(urlEqualTo("/geoip/v2.1/insights/1.1.1.1")) 44 | .willReturn(aResponse() 45 | .withStatus(200) 46 | .withHeader("Content-Type", 47 | "application/vnd.maxmind.com-insights+json; charset=UTF-8; version=2.1") 48 | .withBody(readJsonFile("insights0")))); 49 | wireMock.stubFor(get(urlEqualTo("/geoip/v2.1/insights/1.1.1.2")) 50 | .willReturn(aResponse() 51 | .withStatus(200) 52 | .withHeader("Content-Type", 53 | "application/vnd.maxmind.com-insights+json; charset=UTF-8; version=2.1") 54 | .withBody(readJsonFile("insights1")))); 55 | 56 | WebServiceClient client = new WebServiceClient.Builder(6, "0123456789") 57 | .host("localhost") 58 | .port(wireMock.getPort()) 59 | .disableHttps() 60 | .build(); 61 | 62 | this.insights = client.insights(InetAddress.getByName("1.1.1.1")); 63 | } 64 | 65 | @Test 66 | public void testSubdivisionsList() { 67 | List subdivisionsList = this.insights.getSubdivisions(); 68 | assertNotNull(subdivisionsList, "city.getSubdivisionsList returns null"); 69 | if (subdivisionsList.isEmpty()) { 70 | fail("subdivisionsList is empty"); 71 | } 72 | Subdivision subdivision = subdivisionsList.get(0); 73 | assertEquals( 74 | Integer.valueOf(88), 75 | subdivision.getConfidence(), 76 | "subdivision.getConfidence() does not return 88" 77 | ); 78 | assertEquals( 79 | 574635, 80 | subdivision.getGeoNameId().intValue(), 81 | "subdivision.getGeoNameId() does not return 574635" 82 | ); 83 | assertEquals( 84 | "MN", 85 | subdivision.getIsoCode(), 86 | "subdivision.getCode() does not return MN" 87 | ); 88 | } 89 | 90 | @Test 91 | public void mostSpecificSubdivision() { 92 | assertEquals( 93 | "TT", 94 | this.insights.getMostSpecificSubdivision().getIsoCode(), 95 | "Most specific subdivision returns last subdivision" 96 | ); 97 | } 98 | 99 | @Test 100 | public void leastSpecificSubdivision() { 101 | assertEquals( 102 | "MN", 103 | this.insights.getLeastSpecificSubdivision().getIsoCode(), 104 | "Most specific subdivision returns first subdivision" 105 | ); 106 | } 107 | 108 | @SuppressWarnings("deprecation") 109 | @Test 110 | public void testTraits() { 111 | Traits traits = this.insights.getTraits(); 112 | 113 | assertNotNull(traits, "city.getTraits() returns null"); 114 | assertEquals( 115 | Long.valueOf(1234), 116 | traits.getAutonomousSystemNumber(), 117 | "traits.getAutonomousSystemNumber() does not return 1234" 118 | ); 119 | assertEquals( 120 | 121 | "AS Organization", 122 | traits.getAutonomousSystemOrganization(), 123 | "traits.getAutonomousSystemOrganization() does not return AS Organization" 124 | ); 125 | assertEquals( 126 | 127 | ConnectionType.CABLE_DSL, 128 | traits.getConnectionType(), 129 | "traits.getConnectionType() does not return Cable/DSL" 130 | ); 131 | assertEquals( 132 | "example.com", 133 | traits.getDomain(), 134 | "traits.getDomain() does not return example.com" 135 | ); 136 | assertEquals( 137 | "1.2.3.4", 138 | traits.getIpAddress(), 139 | "traits.getIpAddress() does not return 1.2.3.4" 140 | ); 141 | assertTrue(traits.isAnonymous(), "traits.isAnonymous() returns true"); 142 | assertTrue(traits.isAnonymousProxy(), "traits.isAnonymousProxy() 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.isSatelliteProvider(), "traits.isSatelliteProvider() returns true"); 148 | assertTrue(traits.isTorExitNode(), "traits.isTorExitNode() returns true"); 149 | assertEquals( 150 | "Comcast", 151 | traits.getIsp(), 152 | "traits.getIsp() does not return Comcast" 153 | ); 154 | assertEquals( 155 | "Blorg", 156 | traits.getOrganization(), 157 | "traits.getOrganization() does not return Blorg" 158 | ); 159 | assertEquals( 160 | "college", 161 | traits.getUserType(), 162 | "traits.getUserType() does not return userType" 163 | ); 164 | assertEquals( 165 | Double.valueOf(1.3), 166 | traits.getStaticIpScore(), 167 | "traits.getStaticIpScore() does not return 1.3" 168 | ); 169 | assertEquals( 170 | Integer.valueOf(2), 171 | traits.getUserCount(), 172 | "traits.getUserCount() does not return 2" 173 | ); 174 | } 175 | 176 | @SuppressWarnings("deprecation") 177 | @Test 178 | public void testLocation() { 179 | 180 | Location location = this.insights.getLocation(); 181 | 182 | assertNotNull(location, "city.getLocation() returns null"); 183 | 184 | assertEquals( 185 | Integer.valueOf(24626), 186 | location.getAverageIncome(), 187 | "location.getAverageIncome() does not return 24626" 188 | ); 189 | 190 | assertEquals( 191 | Integer.valueOf(1500), 192 | location.getAccuracyRadius(), 193 | "location.getAccuracyRadius() does not return 1500" 194 | ); 195 | 196 | double latitude = location.getLatitude(); 197 | assertEquals( 198 | 44.98, 199 | latitude, 200 | 0.1, 201 | "location.getLatitude() does not return 44.98" 202 | ); 203 | double longitude = location.getLongitude(); 204 | assertEquals( 205 | 93.2636, 206 | longitude, 207 | 0.1, 208 | "location.getLongitude() does not return 93.2636" 209 | ); 210 | assertEquals( 211 | Integer.valueOf(765), 212 | location.getMetroCode(), 213 | "location.getMetroCode() does not return 765" 214 | ); 215 | assertEquals( 216 | Integer.valueOf(1341), 217 | location.getPopulationDensity(), 218 | "location.getPopulationDensity() does not return 1341" 219 | ); 220 | assertEquals( 221 | "America/Chicago", 222 | location.getTimeZone(), 223 | "location.getTimeZone() does not return America/Chicago" 224 | ); 225 | } 226 | 227 | @Test 228 | public void testMaxMind() { 229 | MaxMind maxmind = this.insights.getMaxMind(); 230 | assertEquals( 231 | 11, maxmind 232 | .getQueriesRemaining().intValue(), 233 | "Correct number of queries remaining" 234 | ); 235 | } 236 | 237 | @Test 238 | public void testPostal() { 239 | 240 | Postal postal = this.insights.getPostal(); 241 | assertEquals( 242 | "55401", 243 | postal.getCode(), 244 | "postal.getCode() does not return 55401" 245 | ); 246 | assertEquals( 247 | Integer.valueOf(33), 248 | postal.getConfidence(), 249 | "postal.getConfidence() does not return 33" 250 | ); 251 | } 252 | 253 | @Test 254 | public void testRepresentedCountry() { 255 | assertNotNull( 256 | this.insights.getRepresentedCountry(), 257 | "city.getRepresentedCountry() returns null" 258 | ); 259 | 260 | assertEquals( 261 | "C", 262 | this.insights.getRepresentedCountry().getType(), 263 | "city.getRepresentedCountry().getType() does not return C" 264 | ); 265 | assertTrue( 266 | this.insights.getRepresentedCountry().isInEuropeanUnion(), 267 | "city.getRepresentedCountry().isInEuropeanUnion() does not return true" 268 | ); 269 | } 270 | 271 | @Test 272 | public void testIsInEuropeanUnion() throws IOException, GeoIp2Exception { 273 | // This uses an alternate fixture where we have the 274 | // is_in_european_union flag set in locations not set in the other 275 | // fixture. 276 | WebServiceClient client = new WebServiceClient.Builder(6, "0123456789") 277 | .host("localhost") 278 | .port(wireMock.getPort()) 279 | .disableHttps() 280 | .build(); 281 | 282 | InsightsResponse insights = client.insights( 283 | InetAddress.getByName("1.1.1.2")); 284 | 285 | assertTrue( 286 | insights.getCountry().isInEuropeanUnion(), 287 | "getCountry().isInEuropeanUnion() does not return true" 288 | ); 289 | assertTrue( 290 | insights.getRegisteredCountry().isInEuropeanUnion(), 291 | "getRegisteredCountry().() isInEuropeanUnion = does not return true" 292 | ); 293 | } 294 | } 295 | -------------------------------------------------------------------------------- /src/test/java/com/maxmind/geoip2/model/JsonTest.java: -------------------------------------------------------------------------------- 1 | package com.maxmind.geoip2.model; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import com.fasterxml.jackson.databind.InjectableValues; 6 | import com.fasterxml.jackson.databind.JsonNode; 7 | import com.fasterxml.jackson.databind.MapperFeature; 8 | import com.fasterxml.jackson.databind.json.JsonMapper; 9 | import com.fasterxml.jackson.jr.ob.JSON; 10 | import java.io.IOException; 11 | import java.util.Collections; 12 | import org.junit.jupiter.api.Test; 13 | 14 | public class JsonTest { 15 | 16 | @Test 17 | public void testInsightsSerialization() throws IOException { 18 | String json = JSON.std 19 | .composeString() 20 | .startObject() 21 | .startObjectField("maxmind") 22 | .put("queries_remaining", 11) 23 | .end() 24 | .startObjectField("registered_country") 25 | .put("geoname_id", 2) 26 | .startObjectField("names") 27 | .put("en", "Canada") 28 | .end() 29 | .put("is_in_european_union", false) 30 | .put("iso_code", "CA") 31 | .end() 32 | .startObjectField("traits") 33 | .put("autonomous_system_organization", "AS Organization") 34 | .put("autonomous_system_number", 1234) 35 | .put("domain", "example.com") 36 | .put("isp", "Comcast") 37 | .put("ip_address", "1.2.3.4") 38 | .put("is_anonymous", true) 39 | .put("is_anonymous_proxy", true) 40 | .put("is_anonymous_vpn", true) 41 | .put("is_anycast", true) 42 | .put("is_hosting_provider", true) 43 | .put("is_legitimate_proxy", true) 44 | .put("is_public_proxy", true) 45 | .put("is_residential_proxy", true) 46 | .put("is_satellite_provider", true) 47 | .put("is_tor_exit_node", true) 48 | .put("network", "1.2.3.0/24") 49 | .put("organization", "Blorg") 50 | .put("user_type", "college") 51 | // This is here just to simplify the testing. We expect the 52 | // difference 53 | .put("is_legitimate_proxy", false) 54 | .end() 55 | .startObjectField("country") 56 | .startObjectField("names") 57 | .put("en", "United States of America") 58 | .end() 59 | .put("geoname_id", 1) 60 | .put("is_in_european_union", false) 61 | .put("iso_code", "US") 62 | .put("confidence", 99) 63 | .end() 64 | .startObjectField("continent") 65 | .startObjectField("names") 66 | .put("en", "North America") 67 | .end() 68 | .put("code", "NA") 69 | .put("geoname_id", 42) 70 | .end() 71 | .startObjectField("location") 72 | .put("average_income", 24626) 73 | .put("population_density", 1341) 74 | .put("time_zone", "America/Chicago") 75 | .put("accuracy_radius", 1500) 76 | .put("metro_code", 765) 77 | .put("latitude", 44.98) 78 | .put("longitude", 93.2636) 79 | .end() 80 | .startArrayField("subdivisions") 81 | .startObject() 82 | .put("confidence", 88) 83 | .put("iso_code", "MN") 84 | .put("geoname_id", 574635) 85 | .startObjectField("names") 86 | .put("en", "Minnesota") 87 | .end() 88 | .end() 89 | .startObject() 90 | .put("iso_code", "TT") 91 | .end() 92 | .end() 93 | .startObjectField("represented_country") 94 | .put("geoname_id", 3) 95 | .startObjectField("names") 96 | .put("en", "United Kingdom") 97 | .end() 98 | .put("type", "C") 99 | .put("is_in_european_union", true) 100 | .put("iso_code", "GB") 101 | .end() 102 | .startObjectField("postal") 103 | .put("code", "55401") 104 | .put("confidence", 33) 105 | .end() 106 | .startObjectField("city") 107 | .put("confidence", 76) 108 | .put("geoname_id", 9876) 109 | .startObjectField("names") 110 | .put("en", "Minneapolis") 111 | .end() 112 | .end() 113 | .end() 114 | .finish(); 115 | 116 | testRoundTrip(InsightsResponse.class, json); 117 | } 118 | 119 | @Test 120 | public void testCitySerialization() throws IOException { 121 | String json = JSON.std 122 | .composeString() 123 | .startObject() 124 | .startObjectField("maxmind") 125 | .put("queries_remaining", 11) 126 | .end() 127 | .startObjectField("registered_country") 128 | .put("geoname_id", 2) 129 | .startObjectField("names") 130 | .put("en", "Canada") 131 | .end() 132 | .put("is_in_european_union", false) 133 | .put("iso_code", "CA") 134 | .end() 135 | .startObjectField("traits") 136 | .put("is_anonymous_proxy", true) 137 | .put("autonomous_system_number", 1234) 138 | .put("isp", "Comcast") 139 | .put("ip_address", "1.2.3.4") 140 | .put("is_satellite_provider", true) 141 | .put("autonomous_system_organization", "AS Organization") 142 | .put("organization", "Blorg") 143 | .put("domain", "example.com") 144 | // These are here just to simplify the testing. We expect the 145 | // difference 146 | .put("is_anonymous", false) 147 | .put("is_anonymous_vpn", false) 148 | .put("is_anycast", true) 149 | .put("is_hosting_provider", false) 150 | .put("is_legitimate_proxy", false) 151 | .put("is_public_proxy", false) 152 | .put("is_residential_proxy", false) 153 | .put("is_tor_exit_node", false) 154 | .put("network", "1.2.3.0/24") 155 | .end() 156 | .startObjectField("country") 157 | .startObjectField("names") 158 | .put("en", "United States of America") 159 | .end() 160 | .put("geoname_id", 1) 161 | .put("is_in_european_union", false) 162 | .put("iso_code", "US") 163 | .end() 164 | .startObjectField("continent") 165 | .startObjectField("names") 166 | .put("en", "North America") 167 | .end() 168 | .put("code", "NA") 169 | .put("geoname_id", 42) 170 | .end() 171 | .startObjectField("location") 172 | .put("time_zone", "America/Chicago") 173 | .put("metro_code", 765) 174 | .put("latitude", 44.98) 175 | .put("longitude", 93.2636) 176 | .end() 177 | .startArrayField("subdivisions") 178 | .startObject() 179 | .put("iso_code", "MN") 180 | .put("geoname_id", 574635) 181 | .startObjectField("names") 182 | .put("en", "Minnesota") 183 | .end() 184 | .end() 185 | .startObject() 186 | .put("iso_code", "TT") 187 | .end() 188 | .end() 189 | .startObjectField("represented_country") 190 | .put("geoname_id", 3) 191 | .startObjectField("names") 192 | .put("en", "United Kingdom") 193 | .end() 194 | .put("type", "C") 195 | .put("is_in_european_union", true) 196 | .put("iso_code", "GB") 197 | .end() 198 | .startObjectField("postal") 199 | .put("code", "55401") 200 | .end() 201 | .startObjectField("city") 202 | .put("geoname_id", 9876) 203 | .startObjectField("names") 204 | .put("en", "Minneapolis") 205 | .end() 206 | .end() 207 | .end() 208 | .finish(); 209 | 210 | testRoundTrip(CityResponse.class, json); 211 | } 212 | 213 | @Test 214 | public void testCountrySerialization() throws IOException { 215 | String json = JSON.std 216 | .composeString() 217 | .startObject() 218 | .startObjectField("maxmind") 219 | .put("queries_remaining", 11) 220 | .end() 221 | .startObjectField("registered_country") 222 | .put("geoname_id", 2) 223 | .startObjectField("names") 224 | .put("en", "Canada") 225 | .end() 226 | .put("is_in_european_union", false) 227 | .put("iso_code", "CA") 228 | .end() 229 | .startObjectField("traits") 230 | .put("is_anonymous_proxy", true) 231 | .put("ip_address", "1.2.3.4") 232 | .put("is_satellite_provider", true) 233 | // These are here just to simplify the testing. We expect the 234 | // difference 235 | .put("is_anonymous", false) 236 | .put("is_anonymous_vpn", false) 237 | .put("is_anycast", true) 238 | .put("is_hosting_provider", false) 239 | .put("is_legitimate_proxy", false) 240 | .put("is_public_proxy", false) 241 | .put("is_residential_proxy", false) 242 | .put("is_tor_exit_node", false) 243 | .put("network", "1.2.3.0/24") 244 | .end() 245 | .startObjectField("country") 246 | .startObjectField("names") 247 | .put("en", "United States of America") 248 | .end() 249 | .put("geoname_id", 1) 250 | .put("is_in_european_union", false) 251 | .put("iso_code", "US") 252 | .end() 253 | .startObjectField("continent") 254 | .startObjectField("names") 255 | .put("en", "North America") 256 | .end() 257 | .put("code", "NA") 258 | .put("geoname_id", 42) 259 | .end() 260 | .startObjectField("represented_country") 261 | .put("geoname_id", 3) 262 | .startObjectField("names") 263 | .put("en", "United Kingdom") 264 | .end() 265 | .put("type", "C") 266 | .put("is_in_european_union", true) 267 | .put("iso_code", "GB") 268 | .end() 269 | .end() 270 | .finish(); 271 | 272 | testRoundTrip(CountryResponse.class, json); 273 | } 274 | 275 | @Test 276 | public void testAnonymousIPSerialization() throws Exception { 277 | String json = JSON.std 278 | .composeString() 279 | .startObject() 280 | .put("is_anonymous", true) 281 | .put("is_anonymous_vpn", true) 282 | .put("is_hosting_provider", true) 283 | .put("is_public_proxy", true) 284 | .put("is_residential_proxy", false) 285 | .put("is_tor_exit_node", true) 286 | .put("ip_address", "1.1.1.1") 287 | .put("network", "1.1.1.0/24") 288 | .end() 289 | .finish(); 290 | 291 | testRoundTrip(AnonymousIpResponse.class, json); 292 | } 293 | 294 | @Test 295 | public void testConnectionTypeSerialization() throws Exception { 296 | String json = JSON.std 297 | .composeString() 298 | .startObject() 299 | .put("connection_type", "Dialup") 300 | .put("ip_address", "1.1.1.1") 301 | .put("network", "1.1.1.0/24") 302 | .end() 303 | .finish(); 304 | 305 | testRoundTrip(ConnectionTypeResponse.class, json); 306 | } 307 | 308 | @Test 309 | public void testDomainSerialization() throws Exception { 310 | String json = JSON.std 311 | .composeString() 312 | .startObject() 313 | .put("domain", "gmail.com") 314 | .put("ip_address", "1.1.1.1") 315 | .put("network", "1.1.1.0/24") 316 | .end() 317 | .finish(); 318 | 319 | testRoundTrip(DomainResponse.class, json); 320 | } 321 | 322 | 323 | @Test 324 | public void testIspSerialization() throws Exception { 325 | String json = JSON.std 326 | .composeString() 327 | .startObject() 328 | .put("autonomous_system_number", 2121) 329 | .put("autonomous_system_organization", "Google, Inc.") 330 | .put("isp", "ISP, Inc.") 331 | .put("organization", "Google, Inc.") 332 | .put("ip_address", "1.1.1.1") 333 | .put("network", "1.1.1.0/24") 334 | .end() 335 | .finish(); 336 | 337 | testRoundTrip(IspResponse.class, json); 338 | } 339 | 340 | protected void testRoundTrip 341 | (Class cls, String json) 342 | throws IOException { 343 | JsonMapper mapper = JsonMapper.builder() 344 | .disable(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS) 345 | .build(); 346 | InjectableValues inject = new InjectableValues.Std().addValue( 347 | "locales", Collections.singletonList("en")); 348 | T response = mapper.readerFor(cls).with(inject).readValue(json); 349 | 350 | JsonNode expectedNode = mapper.readValue(json, JsonNode.class); 351 | JsonNode actualNode = mapper.readValue(response.toJson(), JsonNode.class); 352 | 353 | assertEquals(expectedNode, actualNode); 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /src/test/resources/test-data/city0.json: -------------------------------------------------------------------------------- 1 | { 2 | "continent": { 3 | "code": "NA", 4 | "geoname_id": 42, 5 | "names": { 6 | "zh-CN": "北美洲", 7 | "en": "North America" 8 | } 9 | }, 10 | "country": { 11 | "confidence": 56, 12 | "geoname_id": 1, 13 | "iso_code": "US", 14 | "names": { 15 | "ru": "объединяет государства", 16 | "en": "United States", 17 | "zh-CN": "美国" 18 | } 19 | }, 20 | "registered_country": { 21 | "geoname_id": 2, 22 | "iso_code": "CA", 23 | "names": { 24 | "en": "Canada" 25 | } 26 | }, 27 | "traits": { 28 | "ip_address": "1.2.3.4" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/resources/test-data/country0.json: -------------------------------------------------------------------------------- 1 | { 2 | "traits": { 3 | "ip_address": "1.2.3.4" 4 | }, 5 | "continent": { 6 | "names": { 7 | "en": "North America" 8 | }, 9 | "geoname_id": 42, 10 | "code": "NA" 11 | }, 12 | "country": { 13 | "geoname_id": 1, 14 | "confidence": 56, 15 | "names": { 16 | "en": "United States" 17 | }, 18 | "iso_code": "US" 19 | }, 20 | "registered_country": { 21 | "geoname_id": 2, 22 | "names": { 23 | "en": "Canada" 24 | }, 25 | "iso_code": "CA" 26 | }, 27 | "represented_country": { 28 | "geoname_id": 4, 29 | "type": "military", 30 | "names": { 31 | "en": "United Kingdom" 32 | }, 33 | "is_in_european_union": true, 34 | "iso_code": "GB" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /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 | "metro_code": 765, 30 | "population_density": 1341, 31 | "time_zone": "America/Chicago" 32 | }, 33 | "maxmind": { 34 | "queries_remaining": 11 35 | }, 36 | "postal": { 37 | "code": "55401", 38 | "confidence": 33 39 | }, 40 | "registered_country": { 41 | "geoname_id": 2, 42 | "iso_code": "CA", 43 | "names": { 44 | "en": "Canada" 45 | } 46 | }, 47 | "represented_country": { 48 | "geoname_id": 3, 49 | "is_in_european_union": true, 50 | "iso_code": "GB", 51 | "names": { 52 | "en": "United Kingdom" 53 | }, 54 | "type": "C" 55 | }, 56 | "subdivisions": [ 57 | { 58 | "confidence": 88, 59 | "geoname_id": 574635, 60 | "iso_code": "MN", 61 | "names": { 62 | "en": "Minnesota" 63 | } 64 | }, 65 | { 66 | "iso_code": "TT" 67 | } 68 | ], 69 | "traits": { 70 | "autonomous_system_number": 1234, 71 | "autonomous_system_organization": "AS Organization", 72 | "connection_type": "Cable/DSL", 73 | "domain": "example.com", 74 | "ip_address": "1.2.3.4", 75 | "isp": "Comcast", 76 | "is_anonymous": true, 77 | "is_anonymous_proxy": true, 78 | "is_anonymous_vpn": true, 79 | "is_anycast": true, 80 | "is_hosting_provider": true, 81 | "is_public_proxy": true, 82 | "is_residential_proxy": true, 83 | "is_satellite_provider": true, 84 | "is_tor_exit_node": true, 85 | "organization": "Blorg", 86 | "static_ip_score": 1.3, 87 | "user_count": 2, 88 | "user_type": "college" 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_proxy": true, 94 | "is_anonymous_vpn": true, 95 | "is_anycast": true, 96 | "is_hosting_provider": true, 97 | "is_public_proxy": true, 98 | "is_satellite_provider": true, 99 | "is_tor_exit_node": true, 100 | "organization": "Blorg", 101 | "static_ip_score": 1.3, 102 | "user_count": 2, 103 | "user_type": "college" 104 | } 105 | } --------------------------------------------------------------------------------