Skip to content

Commit 3e4502a

Browse files
authored
Merge pull request #82 from maxmind/development
Merge development branch that drops dependency on jackson-databind
2 parents 4780005 + e0a7dc3 commit 3e4502a

26 files changed

Lines changed: 1390 additions & 342 deletions

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
CHANGELOG
22
=========
33

4+
2.0.0
5+
------------------
6+
* Significant API changes. The `get()` and `getRecord()` methods now take a
7+
class parameter specifying the type of object to deserialize into. You
8+
can either deserialize into a `Map` or to model classes that use the
9+
`MaxMindDbConstructor` and `MaxMindDbParameter` annotations to identify
10+
the constructors and parameters to deserialize into.
11+
* `jackson-databind` is no longer a dependency.
12+
* The `Record` class is now named `DatabaseRecord`. This is to avoid a
13+
conflict with `java.lang.Record` in Java 14.
14+
415
1.4.0 (2020-06-12)
516
------------------
617

README.md

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ format that stores data indexed by IP address subnets (IPv4 or IPv6).
1010

1111
### Maven ###
1212

13-
We recommend installing this package with [Maven](http://maven.apache.org/).
13+
We recommend installing this package with [Maven](https://maven.apache.org/).
1414
To do this, add the dependency to your pom.xml:
1515

1616
```xml
@@ -37,7 +37,7 @@ dependencies {
3737
## Usage ##
3838

3939
*Note:* For accessing MaxMind GeoIP2 databases, we generally recommend using
40-
the [GeoIP2 Java API](http://maxmind.github.io/GeoIP2-java/) rather than using
40+
the [GeoIP2 Java API](https://maxmind.github.io/GeoIP2-java/) rather than using
4141
this package directly.
4242

4343
To use the API, you must first create a `Reader` object. The constructor for
@@ -48,11 +48,9 @@ memory. This often provides performance comparable to loading the file into
4848
real memory with `MEMORY`.
4949

5050
To look up an IP address, pass the address as an `InetAddress` to the `get`
51-
method on `Reader`. This method will return the result as a
52-
`com.fasterxml.jackson.databind.JsonNode` object. `JsonNode` objects are used
53-
as they provide a convenient representation of multi-type data structures and
54-
the databind package of Jackson 2 supplies many tools for interacting with the
55-
data in this format.
51+
method on `Reader`, along with the class of the object you want to
52+
deserialize into. This method will create an instance of the class and
53+
populate it. See examples below.
5654

5755
We recommend reusing the `Reader` object rather than creating a new one for
5856
each lookup. The creation of this object is relatively expensive as it must
@@ -61,7 +59,8 @@ read in metadata for the file.
6159
## Example ##
6260

6361
```java
64-
import com.fasterxml.jackson.databind.JsonNode;
62+
import com.maxmind.db.MaxMindDbConstructor;
63+
import com.maxmind.db.MaxMindDbParameter;
6564
import com.maxmind.db.Reader;
6665
import com.maxmind.db.Record;
6766

@@ -73,26 +72,56 @@ public class Lookup {
7372
public static void main(String[] args) throws IOException {
7473
File database = new File("/path/to/database/GeoIP2-City.mmdb");
7574
try (Reader reader = new Reader(database)) {
76-
7775
InetAddress address = InetAddress.getByName("24.24.24.24");
7876

7977
// get() returns just the data for the associated record
80-
JsonNode recordData = reader.get(address);
78+
LookupResult result = reader.get(address, LookupResult.class);
8179

82-
System.out.println(recordData);
80+
System.out.println(result.getCountry().getIsoCode());
8381

8482
// getRecord() returns a Record class that contains both
8583
// the data for the record and associated metadata.
86-
Record record = reader.getRecord(address);
84+
Record<LookupResult> record
85+
= reader.getRecord(address, LookupResult.class);
8786

88-
System.out.println(record.getData());
87+
System.out.println(record.getData().getCountry().getIsoCode());
8988
System.out.println(record.getNetwork());
9089
}
9190
}
91+
92+
public static class LookupResult {
93+
private final Country country;
94+
95+
@MaxMindDbConstructor
96+
public LookupResult (
97+
@MaxMindDbParameter(name="country") Country country
98+
) {
99+
this.country = country;
100+
}
101+
102+
public Country getCountry() {
103+
return this.country;
104+
}
105+
}
106+
107+
public static class Country {
108+
private final String isoCode;
109+
110+
@MaxMindDbConstructor
111+
public Country (
112+
@MaxMindDbParameter(name="iso_code") String isoCode
113+
) {
114+
this.isoCode = isoCode;
115+
}
116+
117+
public String getIsoCode() {
118+
return this.isoCode;
119+
}
120+
}
92121
}
93122
```
94123

95-
### Caching ###
124+
## Caching ##
96125

97126
The database API supports pluggable caching (by default, no caching is
98127
performed). A simple implementation is provided by `com.maxmind.db.CHMCache`.
@@ -105,6 +134,10 @@ Usage:
105134
Reader reader = new Reader(database, new CHMCache());
106135
```
107136

137+
Please note that the cache will hold references to the objects created
138+
during the lookup. If you mutate the objects, the mutated objects will be
139+
returned from the cache on subsequent lookups.
140+
108141
## Multi-Threaded Use ##
109142

110143
This API fully supports use in multi-threaded applications. In such
@@ -130,7 +163,7 @@ version. You may also call `System.gc()` after dereferencing the
130163

131164
If you are packaging the database file as a resource in a JAR file using
132165
Maven, you must
133-
[disable binary file filtering](http://maven.apache.org/plugins/maven-resources-plugin/examples/binaries-filtering.html).
166+
[disable binary file filtering](https://maven.apache.org/plugins/maven-resources-plugin/examples/binaries-filtering.html).
134167
Failure to do so will result in `InvalidDatabaseException` exceptions being
135168
thrown when querying the database.
136169

@@ -139,18 +172,18 @@ thrown when querying the database.
139172
The MaxMind DB format is an open format for quickly mapping IP addresses to
140173
records. The
141174
[specification](https://github.com/maxmind/MaxMind-DB/blob/master/MaxMind-DB-spec.md)
142-
is available as part of our
175+
is available, as is our
143176
[Perl writer](https://github.com/maxmind/MaxMind-DB-Writer-perl) for the
144177
format.
145178

146179
## Bug Tracker ##
147180

148-
Please report all issues with this code using the [GitHub issue tracker]
149-
(https://github.com/maxmind/MaxMind-DB-Reader-java/issues).
181+
Please report all issues with this code using the [GitHub issue
182+
tracker](https://github.com/maxmind/MaxMind-DB-Reader-java/issues).
150183

151184
If you are having an issue with a MaxMind database or service that is not
152185
specific to this reader, please [contact MaxMind support]
153-
(http://www.maxmind.com/en/support).
186+
(https://www.maxmind.com/en/support).
154187

155188
## Requirements ##
156189

@@ -163,7 +196,7 @@ possible.
163196

164197
## Versioning ##
165198

166-
The MaxMind DB Reader API uses [Semantic Versioning](http://semver.org/).
199+
The MaxMind DB Reader API uses [Semantic Versioning](https://semver.org/).
167200

168201
## Copyright and License ##
169202

pom.xml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>com.maxmind.db</groupId>
55
<artifactId>maxmind-db</artifactId>
6-
<version>1.4.1-SNAPSHOT</version>
6+
<version>2.0.0-SNAPSHOT</version>
77
<packaging>jar</packaging>
88
<name>MaxMind DB Reader</name>
99
<description>Reader for MaxMind DB</description>
@@ -42,11 +42,6 @@
4242
<version>4.13</version>
4343
<scope>test</scope>
4444
</dependency>
45-
<dependency>
46-
<groupId>com.fasterxml.jackson.core</groupId>
47-
<artifactId>jackson-databind</artifactId>
48-
<version>2.11.0</version>
49-
</dependency>
5045
</dependencies>
5146
<build>
5247
<plugins>

sample/Benchmark.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import java.io.File;
22
import java.io.IOException;
33
import java.net.InetAddress;
4+
import java.util.Map;
45
import java.util.Random;
56

6-
import com.fasterxml.jackson.databind.JsonNode;
77
import com.maxmind.db.CHMCache;
88
import com.maxmind.db.InvalidDatabaseException;
99
import com.maxmind.db.NoCache;
@@ -45,7 +45,7 @@ private static void bench(Reader r, int count, int seed) throws IOException {
4545
for (int i = 0; i < count; i++) {
4646
random.nextBytes(address);
4747
InetAddress ip = InetAddress.getByAddress(address);
48-
JsonNode t = r.get(ip);
48+
Map t = r.get(ip, Map.class);
4949
if (TRACE) {
5050
if (i % 50000 == 0) {
5151
System.out.println(i + " " + ip);

src/main/java/com/maxmind/db/CHMCache.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import java.io.IOException;
44
import java.util.concurrent.ConcurrentHashMap;
55

6-
import com.fasterxml.jackson.databind.JsonNode;
7-
86
/**
97
* A simplistic cache using a {@link ConcurrentHashMap}. There's no eviction
108
* policy, it just fills up until reaching the specified capacity <small>(or
@@ -15,7 +13,7 @@ public class CHMCache implements NodeCache {
1513
private static final int DEFAULT_CAPACITY = 4096;
1614

1715
private final int capacity;
18-
private final ConcurrentHashMap<Integer, JsonNode> cache;
16+
private final ConcurrentHashMap<CacheKey, DecodedValue> cache;
1917
private boolean cacheFull = false;
2018

2119
public CHMCache() {
@@ -28,14 +26,13 @@ public CHMCache(int capacity) {
2826
}
2927

3028
@Override
31-
public JsonNode get(int key, Loader loader) throws IOException {
32-
Integer k = key;
33-
JsonNode value = cache.get(k);
29+
public DecodedValue get(CacheKey key, Loader loader) throws IOException {
30+
DecodedValue value = cache.get(key);
3431
if (value == null) {
3532
value = loader.load(key);
3633
if (!cacheFull) {
3734
if (cache.size() < capacity) {
38-
cache.put(k, value);
35+
cache.put(key, value);
3936
} else {
4037
cacheFull = true;
4138
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.maxmind.db;
2+
3+
public final class CacheKey<T> {
4+
private final int offset;
5+
private final Class<T> cls;
6+
private final java.lang.reflect.Type type;
7+
8+
CacheKey(int offset, Class<T> cls, java.lang.reflect.Type type) {
9+
this.offset = offset;
10+
this.cls = cls;
11+
this.type = type;
12+
}
13+
14+
int getOffset() {
15+
return this.offset;
16+
}
17+
18+
Class<T> getCls() {
19+
return this.cls;
20+
}
21+
22+
java.lang.reflect.Type getType() {
23+
return this.type;
24+
}
25+
26+
@Override
27+
public boolean equals(Object o) {
28+
if (o == null) {
29+
return false;
30+
}
31+
32+
CacheKey other = (CacheKey) o;
33+
34+
if (this.offset != other.offset) {
35+
return false;
36+
}
37+
38+
if (this.cls == null) {
39+
if (other.cls != null) {
40+
return false;
41+
}
42+
} else if (!this.cls.equals(other.cls)) {
43+
return false;
44+
}
45+
46+
if (this.type == null) {
47+
return other.type == null;
48+
}
49+
return this.type.equals(other.type);
50+
}
51+
52+
@Override
53+
public int hashCode() {
54+
int result = offset;
55+
result = 31 * result + (cls == null ? 0 : cls.hashCode());
56+
result = 31 * result + (type == null ? 0 : type.hashCode());
57+
return result;
58+
}
59+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.maxmind.db;
2+
3+
import java.lang.reflect.Constructor;
4+
import java.util.Map;
5+
6+
final class CachedConstructor<T> {
7+
private final Constructor<T> constructor;
8+
private final Class<?>[] parameterTypes;
9+
private final java.lang.reflect.Type[] parameterGenericTypes;
10+
private final Map<String, Integer> parameterIndexes;
11+
12+
CachedConstructor(
13+
Constructor<T> constructor,
14+
Class<?>[] parameterTypes,
15+
java.lang.reflect.Type[] parameterGenericTypes,
16+
Map<String, Integer> parameterIndexes
17+
) {
18+
this.constructor = constructor;
19+
this.parameterTypes = parameterTypes;
20+
this.parameterGenericTypes = parameterGenericTypes;
21+
this.parameterIndexes = parameterIndexes;
22+
}
23+
24+
Constructor<T> getConstructor() {
25+
return this.constructor;
26+
}
27+
28+
Class<?>[] getParameterTypes() {
29+
return this.parameterTypes;
30+
}
31+
32+
java.lang.reflect.Type[] getParameterGenericTypes() {
33+
return this.parameterGenericTypes;
34+
}
35+
36+
Map<String, Integer> getParameterIndexes() {
37+
return this.parameterIndexes;
38+
}
39+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.maxmind.db;
2+
3+
/**
4+
* Signals that no annotated constructor was found. You should annotate a
5+
* constructor in the class with the MaxMindDbConstructor annotation.
6+
*/
7+
public class ConstructorNotFoundException extends RuntimeException {
8+
private static final long serialVersionUID = 1L;
9+
10+
ConstructorNotFoundException(String message) {
11+
super(message);
12+
}
13+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.maxmind.db;
2+
3+
final class CtrlData {
4+
private final Type type;
5+
private final int ctrlByte;
6+
private final int offset;
7+
private final int size;
8+
9+
CtrlData(Type type, int ctrlByte, int offset, int size) {
10+
this.type = type;
11+
this.ctrlByte = ctrlByte;
12+
this.offset = offset;
13+
this.size = size;
14+
}
15+
16+
public Type getType() {
17+
return this.type;
18+
}
19+
20+
public int getCtrlByte() {
21+
return this.ctrlByte;
22+
}
23+
24+
public int getOffset() {
25+
return this.offset;
26+
}
27+
28+
public int getSize() {
29+
return this.size;
30+
}
31+
}

0 commit comments

Comments
 (0)