From 3923db0677c170119eb934b2ee506a77da759a42 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Tue, 20 Nov 2018 11:03:47 +0000
Subject: [PATCH] Modify MaxMind-DB-Reader-java to remove the dependency on the
 large com.fasterxml.jackson.databind JSON package, and use POJOs instead.

---
 router/java/src/com/maxmind/db/CHMCache.java  | 10 ++-
 router/java/src/com/maxmind/db/Decoder.java   | 70 +++++++++----------
 router/java/src/com/maxmind/db/Metadata.java  | 61 +++++++++-------
 router/java/src/com/maxmind/db/NoCache.java   |  4 +-
 router/java/src/com/maxmind/db/NodeCache.java |  6 +-
 router/java/src/com/maxmind/db/Reader.java    |  9 ++-
 6 files changed, 80 insertions(+), 80 deletions(-)

diff --git a/router/java/src/com/maxmind/db/CHMCache.java b/router/java/src/com/maxmind/db/CHMCache.java
index 058db62d91..adcfbd52d7 100644
--- a/router/java/src/com/maxmind/db/CHMCache.java
+++ b/router/java/src/com/maxmind/db/CHMCache.java
@@ -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) {
diff --git a/router/java/src/com/maxmind/db/Decoder.java b/router/java/src/com/maxmind/db/Decoder.java
index 5396a11881..0ca4774ffa 100644
--- a/router/java/src/com/maxmind/db/Decoder.java
+++ b/router/java/src/com/maxmind/db/Decoder.java
@@ -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) {
diff --git a/router/java/src/com/maxmind/db/Metadata.java b/router/java/src/com/maxmind/db/Metadata.java
index e31bd25920..b15d256b62 100644
--- a/router/java/src/com/maxmind/db/Metadata.java
+++ b/router/java/src/com/maxmind/db/Metadata.java
@@ -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;
     }
 
     /**
diff --git a/router/java/src/com/maxmind/db/NoCache.java b/router/java/src/com/maxmind/db/NoCache.java
index 45276a2767..c6f26814d1 100644
--- a/router/java/src/com/maxmind/db/NoCache.java
+++ b/router/java/src/com/maxmind/db/NoCache.java
@@ -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);
     }
 
diff --git a/router/java/src/com/maxmind/db/NodeCache.java b/router/java/src/com/maxmind/db/NodeCache.java
index f1c7363546..cd272c1afc 100644
--- a/router/java/src/com/maxmind/db/NodeCache.java
+++ b/router/java/src/com/maxmind/db/NodeCache.java
@@ -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;
 
 }
diff --git a/router/java/src/com/maxmind/db/Reader.java b/router/java/src/com/maxmind/db/Reader.java
index 32d0b86457..65a705097f 100644
--- a/router/java/src/com/maxmind/db/Reader.java
+++ b/router/java/src/com/maxmind/db/Reader.java
@@ -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();
-- 
GitLab