Modify MaxMind-DB-Reader-java

to remove the dependency on the large com.fasterxml.jackson.databind JSON package,
and use POJOs instead.
This commit is contained in:
zzz
2018-11-20 11:03:47 +00:00
parent 98de1ae404
commit 3923db0677
6 changed files with 80 additions and 80 deletions

View File

@ -3,8 +3,6 @@ package com.maxmind.db;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import com.fasterxml.jackson.databind.JsonNode;
/**
* A simplistic cache using a {@link ConcurrentHashMap}. There's no eviction
* policy, it just fills up until reaching the specified capacity <small>(or
@ -15,7 +13,7 @@ public class CHMCache implements NodeCache {
private static final int DEFAULT_CAPACITY = 4096;
private final int capacity;
private final ConcurrentHashMap<Integer, JsonNode> cache;
private final ConcurrentHashMap<Integer, Object> cache;
private boolean cacheFull = false;
public CHMCache() {
@ -24,13 +22,13 @@ public class CHMCache implements NodeCache {
public CHMCache(int capacity) {
this.capacity = capacity;
this.cache = new ConcurrentHashMap<Integer, JsonNode>(capacity);
this.cache = new ConcurrentHashMap<Integer, Object>(capacity);
}
@Override
public JsonNode get(int key, Loader loader) throws IOException {
public Object get(int key, Loader loader) throws IOException {
Integer k = key;
JsonNode value = cache.get(k);
Object value = cache.get(k);
if (value == null) {
value = loader.load(key);
if (!cacheFull) {

View File

@ -12,10 +12,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.*;
/*
* Decoder for MaxMind DB data.
*
@ -25,8 +21,6 @@ final class Decoder {
private static final Charset UTF_8 = Charset.forName("UTF-8");
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final int[] POINTER_VALUE_OFFSETS = { 0, 0, 1 << 11, (1 << 19) + ((1) << 11), 0 };
// XXX - This is only for unit testings. We should possibly make a
@ -71,12 +65,12 @@ final class Decoder {
private final NodeCache.Loader cacheLoader = new NodeCache.Loader() {
@Override
public JsonNode load(int key) throws IOException {
public Object load(int key) throws IOException {
return decode(key);
}
};
JsonNode decode(int offset) throws IOException {
Object decode(int offset) throws IOException {
if (offset >= this.buffer.capacity()) {
throw new InvalidDatabaseException(
"The MaxMind DB file's data section contains bad data: "
@ -87,7 +81,7 @@ final class Decoder {
return decode();
}
JsonNode decode() throws IOException {
Object decode() throws IOException {
int ctrlByte = 0xFF & this.buffer.get();
Type type = Type.fromControlByte(ctrlByte);
@ -103,12 +97,12 @@ final class Decoder {
// for unit testing
if (this.POINTER_TEST_HACK) {
return new LongNode(pointer);
return Long.valueOf(pointer);
}
int targetOffset = (int) pointer;
int position = buffer.position();
JsonNode node = cache.get(targetOffset, cacheLoader);
Object node = cache.get(targetOffset, cacheLoader);
buffer.position(position);
return node;
}
@ -147,7 +141,7 @@ final class Decoder {
return this.decodeByType(type, size);
}
private JsonNode decodeByType(Type type, int size)
private Object decodeByType(Type type, int size)
throws IOException {
switch (type) {
case MAP:
@ -157,13 +151,13 @@ final class Decoder {
case BOOLEAN:
return Decoder.decodeBoolean(size);
case UTF8_STRING:
return new TextNode(this.decodeString(size));
return this.decodeString(size);
case DOUBLE:
return this.decodeDouble(size);
case FLOAT:
return this.decodeFloat(size);
case BYTES:
return new BinaryNode(this.getByteArray(size));
return this.getByteArray(size);
case UINT16:
return this.decodeUint16(size);
case UINT32:
@ -188,12 +182,12 @@ final class Decoder {
return s;
}
private IntNode decodeUint16(int size) {
return new IntNode(this.decodeInteger(size));
private Integer decodeUint16(int size) {
return Integer.valueOf(this.decodeInteger(size));
}
private IntNode decodeInt32(int size) {
return new IntNode(this.decodeInteger(size));
private Integer decodeInt32(int size) {
return Integer.valueOf(this.decodeInteger(size));
}
private long decodeLong(int size) {
@ -204,8 +198,8 @@ final class Decoder {
return integer;
}
private LongNode decodeUint32(int size) {
return new LongNode(this.decodeLong(size));
private Long decodeUint32(int size) {
return Long.valueOf(this.decodeLong(size));
}
private int decodeInteger(int size) {
@ -224,36 +218,36 @@ final class Decoder {
return integer;
}
private BigIntegerNode decodeBigInteger(int size) {
private BigInteger decodeBigInteger(int size) {
byte[] bytes = this.getByteArray(size);
return new BigIntegerNode(new BigInteger(1, bytes));
return new BigInteger(1, bytes);
}
private DoubleNode decodeDouble(int size) throws InvalidDatabaseException {
private Double decodeDouble(int size) throws InvalidDatabaseException {
if (size != 8) {
throw new InvalidDatabaseException(
"The MaxMind DB file's data section contains bad data: "
+ "invalid size of double.");
}
return new DoubleNode(this.buffer.getDouble());
return Double.valueOf(this.buffer.getDouble());
}
private FloatNode decodeFloat(int size) throws InvalidDatabaseException {
private Float decodeFloat(int size) throws InvalidDatabaseException {
if (size != 4) {
throw new InvalidDatabaseException(
"The MaxMind DB file's data section contains bad data: "
+ "invalid size of float.");
}
return new FloatNode(this.buffer.getFloat());
return Float.valueOf(this.buffer.getFloat());
}
private static BooleanNode decodeBoolean(int size)
private static Boolean decodeBoolean(int size)
throws InvalidDatabaseException {
switch (size) {
case 0:
return BooleanNode.FALSE;
return Boolean.FALSE;
case 1:
return BooleanNode.TRUE;
return Boolean.TRUE;
default:
throw new InvalidDatabaseException(
"The MaxMind DB file's data section contains bad data: "
@ -261,28 +255,28 @@ final class Decoder {
}
}
private JsonNode decodeArray(int size) throws IOException {
private List<Object> decodeArray(int size) throws IOException {
List<JsonNode> array = new ArrayList<JsonNode>(size);
List<Object> array = new ArrayList<Object>(size);
for (int i = 0; i < size; i++) {
JsonNode r = this.decode();
Object r = this.decode();
array.add(r);
}
return new ArrayNode(OBJECT_MAPPER.getNodeFactory(), Collections.unmodifiableList(array));
return Collections.unmodifiableList(array);
}
private JsonNode decodeMap(int size) throws IOException {
private Map<String, Object> decodeMap(int size) throws IOException {
int capacity = (int) (size / 0.75F + 1.0F);
Map<String, JsonNode> map = new HashMap<String, JsonNode>(capacity);
Map<String, Object> map = new HashMap<String, Object>(capacity);
for (int i = 0; i < size; i++) {
String key = this.decode().asText();
JsonNode value = this.decode();
String key = (String) this.decode();
Object value = this.decode();
map.put(key, value);
}
return new ObjectNode(OBJECT_MAPPER.getNodeFactory(), Collections.unmodifiableMap(map));
return Collections.unmodifiableMap(map);
}
private byte[] getByteArray(int length) {

View File

@ -6,10 +6,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public final class Metadata {
private final int binaryFormatMajorVersion;
private final int binaryFormatMinorVersion;
@ -18,11 +14,11 @@ public final class Metadata {
private final String databaseType;
private final JsonNode description;
private final Map description;
private final int ipVersion;
private final JsonNode languages;
private final List languages;
private final int nodeByteSize;
@ -32,22 +28,43 @@ public final class Metadata {
private final int searchTreeSize;
Metadata(JsonNode metadata) {
this.binaryFormatMajorVersion = metadata.get(
"binary_format_major_version").asInt();
this.binaryFormatMinorVersion = metadata.get(
"binary_format_minor_version").asInt();
this.buildEpoch = metadata.get("build_epoch").asLong();
this.databaseType = metadata.get("database_type").asText();
this.languages = metadata.get("languages");
this.description = metadata.get("description");
this.ipVersion = metadata.get("ip_version").asInt();
this.nodeCount = metadata.get("node_count").asInt();
this.recordSize = metadata.get("record_size").asInt();
Metadata(Map metadata) {
this.binaryFormatMajorVersion = getInt(metadata,
"binary_format_major_version");
this.binaryFormatMinorVersion = getInt(metadata,
"binary_format_minor_version");
this.buildEpoch = getLong(metadata, "build_epoch");
this.databaseType = getString(metadata, "database_type");
this.languages = (List) metadata.get("languages");
this.description = (Map) metadata.get("description");
this.ipVersion = getInt(metadata, "ip_version");
this.nodeCount = getInt(metadata, "node_count");
this.recordSize = getInt(metadata, "record_size");
this.nodeByteSize = this.recordSize / 4;
this.searchTreeSize = this.nodeCount * this.nodeByteSize;
}
private static int getInt(Object m, String key) {
Map map = (Map) m;
Number i = (Number) map.get(key);
if (i != null)
return i.intValue();
return 0;
}
private static long getLong(Object m, String key) {
Map map = (Map) m;
Number i = (Number) map.get(key);
if (i != null)
return i.longValue();
return 0;
}
private static String getString(Object m, String key) {
Map map = (Map) m;
return (String) map.get(key);
}
/**
* @return the major version number for the database's binary format.
*/
@ -82,9 +99,7 @@ public final class Metadata {
* @return map from language code to description in that language.
*/
public Map<String, String> getDescription() {
return new ObjectMapper().convertValue(this.description,
new TypeReference<HashMap<String, String>>() {
});
return this.description;
}
/**
@ -99,9 +114,7 @@ public final class Metadata {
* @return list of languages supported by the database.
*/
public List<String> getLanguages() {
return new ObjectMapper().convertValue(this.languages,
new TypeReference<ArrayList<String>>() {
});
return this.languages;
}
/**

View File

@ -2,8 +2,6 @@ package com.maxmind.db;
import java.io.IOException;
import com.fasterxml.jackson.databind.JsonNode;
/**
* A no-op cache singleton.
*/
@ -15,7 +13,7 @@ public class NoCache implements NodeCache {
}
@Override
public JsonNode get(int key, Loader loader) throws IOException {
public Object get(int key, Loader loader) throws IOException {
return loader.load(key);
}

View File

@ -2,14 +2,12 @@ package com.maxmind.db;
import java.io.IOException;
import com.fasterxml.jackson.databind.JsonNode;
public interface NodeCache {
public interface Loader {
JsonNode load(int key) throws IOException;
Object load(int key) throws IOException;
}
public JsonNode get(int key, Loader loader) throws IOException;
public Object get(int key, Loader loader) throws IOException;
}

View File

@ -6,10 +6,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import com.fasterxml.jackson.databind.JsonNode;
/**
* Instances of this class provide a reader for the MaxMind DB format. IP
* addresses can be looked up using the <code>get</code> method.
@ -129,7 +128,7 @@ public final class Reader implements Closeable {
int start = this.findMetadataStart(buffer, name);
Decoder metadataDecoder = new Decoder(this.cache, buffer, start);
this.metadata = new Metadata(metadataDecoder.decode(start));
this.metadata = new Metadata((Map) metadataDecoder.decode(start));
this.ipV4Start = this.findIpV4StartNode(buffer);
}
@ -141,7 +140,7 @@ public final class Reader implements Closeable {
* @return the record for the IP address.
* @throws IOException if a file I/O error occurs.
*/
public JsonNode get(InetAddress ipAddress) throws IOException {
public Object get(InetAddress ipAddress) throws IOException {
ByteBuffer buffer = this.getBufferHolder().get();
int pointer = this.findAddressInTree(buffer, ipAddress);
if (pointer == 0) {
@ -234,7 +233,7 @@ public final class Reader implements Closeable {
}
}
private JsonNode resolveDataPointer(ByteBuffer buffer, int pointer)
private Object resolveDataPointer(ByteBuffer buffer, int pointer)
throws IOException {
int resolved = (pointer - this.metadata.getNodeCount())
+ this.metadata.getSearchTreeSize();