Repository: graphhopper/graphhopper
Pull request #1044 (2017-04-27 14:46:51)

switch from json.org to jackson - minimal version
Replaces json.org with jackson. Basically 1:1, without making much use of its features yet.

This does _not_ mean we can't switch to Gson. On the contrary, those two are very similar, and at the moment it would be search+replace, I think.

karussell: Thanks! And +1 for jackson for now ...
karussell: Thanks, I will merge. (this time I can squash I guess?)
karussell: This then fixes #773 I think (?) and would you mind to do similar work for the map matching :) ? 
michaz: > Thanks, I will merge. (this time I can squash I guess?)
Yes please.

Patch:
diff --git a/core/pom.xml b/core/pom.xml
index 62f259761..e0e51e307 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -81,9 +81,9 @@
             <version>${jackson.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.json</groupId>
-            <artifactId>json</artifactId>
-            <version>${json.org.version}</version>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>${jackson.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/pom.xml b/pom.xml
index 2ca01579f..3cc59b1d4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,7 +17,6 @@
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <slf4j.version>1.7.21</slf4j.version>
         <log4j.version>1.2.17</log4j.version>
-        <json.org.version>20160810</json.org.version>
         <commons-compress.version>1.12</commons-compress.version>
         <jackson.version>2.8.4</jackson.version>
 
diff --git a/web/pom.xml b/web/pom.xml
index a1b5d93fd..4bc5ce2c2 100644
--- a/web/pom.xml
+++ b/web/pom.xml
@@ -36,11 +36,7 @@
             <version>${project.parent.version}</version>
         </dependency>
 
-        <dependency>
-            <groupId>org.json</groupId>
-            <artifactId>json</artifactId>
-            <version>${json.org.version}</version>
-        </dependency>
+
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
diff --git a/web/src/main/java/com/graphhopper/http/ChangeGraphServlet.java b/web/src/main/java/com/graphhopper/http/ChangeGraphServlet.java
index 526594010..3527d318b 100644
--- a/web/src/main/java/com/graphhopper/http/ChangeGraphServlet.java
+++ b/web/src/main/java/com/graphhopper/http/ChangeGraphServlet.java
@@ -17,22 +17,21 @@
  */
 package com.graphhopper.http;
 
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.graphhopper.GraphHopper;
 import com.graphhopper.GraphHopperAPI;
+import com.graphhopper.json.GHJson;
 import com.graphhopper.json.geo.JsonFeatureCollection;
 import com.graphhopper.storage.change.ChangeGraphResponse;
 import com.graphhopper.util.Helper;
 import com.graphhopper.util.StopWatch;
 
-import java.io.IOException;
-import java.io.InputStreamReader;
 import javax.inject.Inject;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-
-import org.json.JSONObject;
-import com.graphhopper.json.GHJson;
+import java.io.IOException;
+import java.io.InputStreamReader;
 
 /**
  * This class defines a new endpoint to submit access and speed changes to the graph.
@@ -60,7 +59,7 @@ public class ChangeGraphServlet extends GHBaseServlet {
             }
             // TODO make asynchronous!
             ChangeGraphResponse rsp = ((GraphHopper) graphHopper).changeGraph(collection.getFeatures());
-            JSONObject resObject = new JSONObject();
+            ObjectNode resObject = jsonNodeFactory.objectNode();
             resObject.put("updates", rsp.getUpdateCount());
             // prepare the consumer to get some changes not immediately when returning after POST
             resObject.put("scheduled_updates", 0);
diff --git a/web/src/main/java/com/graphhopper/http/GHBaseServlet.java b/web/src/main/java/com/graphhopper/http/GHBaseServlet.java
index 314ebb032..483a2903d 100644
--- a/web/src/main/java/com/graphhopper/http/GHBaseServlet.java
+++ b/web/src/main/java/com/graphhopper/http/GHBaseServlet.java
@@ -17,10 +17,13 @@
  */
 package com.graphhopper.http;
 
-import com.graphhopper.GHRequest;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.graphhopper.routing.util.HintsMap;
-import org.json.JSONException;
-import org.json.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,55 +46,52 @@ import static javax.servlet.http.HttpServletResponse.SC_OK;
  */
 public class GHBaseServlet extends HttpServlet {
     protected static final Logger logger = LoggerFactory.getLogger(GHBaseServlet.class);
+    protected final JsonNodeFactory jsonNodeFactory = new JsonNodeFactory(false);
+
+    @Inject
+    protected ObjectMapper objectMapper;
+
     @Inject
     @Named("jsonp_allowed")
     private boolean jsonpAllowed;
 
-    protected void writeJson(HttpServletRequest req, HttpServletResponse res, JSONObject json) throws JSONException, IOException {
+    protected void writeJson(HttpServletRequest req, HttpServletResponse res, JsonNode json) throws IOException {
         String type = getParam(req, "type", "json");
         res.setCharacterEncoding("UTF-8");
-        boolean debug = getBooleanParam(req, "debug", false) || getBooleanParam(req, "pretty", false);
+        final boolean indent = getBooleanParam(req, "debug", false) || getBooleanParam(req, "pretty", false);
+        ObjectWriter objectWriter = indent ? objectMapper.writer().with(SerializationFeature.INDENT_OUTPUT) : objectMapper.writer();
         if ("jsonp".equals(type)) {
             res.setContentType("application/javascript");
             if (!jsonpAllowed) {
                 writeError(res, SC_BAD_REQUEST, "Server is not configured to allow jsonp!");
                 return;
             }
-
             String callbackName = getParam(req, "callback", null);
             if (callbackName == null) {
                 writeError(res, SC_BAD_REQUEST, "No callback provided, necessary if type=jsonp");
                 return;
             }
-
-            if (debug)
-                writeResponse(res, callbackName + "(" + json.toString(2) + ")");
-            else
-                writeResponse(res, callbackName + "(" + json.toString(0) + ")");
-
+            writeResponse(res, callbackName + "(" + objectWriter.writeValueAsString(json) + ")");
         } else {
             res.setContentType("application/json");
-            if (debug)
-                writeResponse(res, json.toString(2));
-            else
-                writeResponse(res, json.toString(0));
+            writeResponse(res, objectWriter.writeValueAsString(json));
         }
     }
 
     protected void writeError(HttpServletResponse res, int code, String message) {
-        JSONObject json = new JSONObject();
+        ObjectNode json = jsonNodeFactory.objectNode();
         json.put("message", message);
         writeJsonError(res, code, json);
     }
 
-    protected void writeJsonError(HttpServletResponse res, int code, JSONObject json) {
+    protected void writeJsonError(HttpServletResponse res, int code, JsonNode json) {
         try {
             // no type parameter check here as jsonp does not work if an error
             // also no debug parameter yet
             res.setContentType("application/json");
             res.setCharacterEncoding("UTF-8");
             res.setStatus(code);
-            res.getWriter().append(json.toString(2));
+            res.getWriter().append(objectMapper.writer().with(SerializationFeature.INDENT_OUTPUT).writeValueAsString(json));
         } catch (IOException ex) {
             throw new RuntimeException("Cannot write JSON Error " + code, ex);
         }
diff --git a/web/src/main/java/com/graphhopper/http/GraphHopperServlet.java b/web/src/main/java/com/graphhopper/http/GraphHopperServlet.java
index f0c490d3c..64c4176cc 100644
--- a/web/src/main/java/com/graphhopper/http/GraphHopperServlet.java
+++ b/web/src/main/java/com/graphhopper/http/GraphHopperServlet.java
@@ -17,12 +17,14 @@
  */
 package com.graphhopper.http;
 
-import com.graphhopper.*;
+import com.graphhopper.GHRequest;
+import com.graphhopper.GHResponse;
+import com.graphhopper.GraphHopperAPI;
+import com.graphhopper.PathWrapper;
 import com.graphhopper.routing.util.EncodingManager;
 import com.graphhopper.routing.util.FlagEncoder;
 import com.graphhopper.util.StopWatch;
 import com.graphhopper.util.shapes.GHPoint;
-import org.json.JSONObject;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
@@ -182,9 +184,9 @@ public class GraphHopperServlet extends GHBaseServlet {
                 ((Map) infoMap).put("took", Math.round(took * 1000));
 
             if (ghRsp.hasErrors())
-                writeJsonError(httpRes, SC_BAD_REQUEST, new JSONObject(map));
+                writeJsonError(httpRes, SC_BAD_REQUEST, jsonNodeFactory.pojoNode(map));
             else {
-                writeJson(httpReq, httpRes, new JSONObject(map));
+                writeJson(httpReq, httpRes, jsonNodeFactory.pojoNode(map));
             }
         }
     }
diff --git a/web/src/main/java/com/graphhopper/http/GraphHopperServletModule.java b/web/src/main/java/com/graphhopper/http/GraphHopperServletModule.java
index 9219f38ed..c6e359c92 100644
--- a/web/src/main/java/com/graphhopper/http/GraphHopperServletModule.java
+++ b/web/src/main/java/com/graphhopper/http/GraphHopperServletModule.java
@@ -17,12 +17,25 @@
  */
 package com.graphhopper.http;
 
+import com.bedatadriven.jackson.datatype.jts.JtsModule;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.BeanDescription;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationConfig;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
+import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
+import com.google.inject.Provides;
 import com.google.inject.servlet.ServletModule;
 import com.graphhopper.util.CmdArgs;
 
 import javax.inject.Singleton;
+import java.text.SimpleDateFormat;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * @author Peter Karich
@@ -71,4 +84,32 @@ public class GraphHopperServletModule extends ServletModule {
         serve("/change*").with(ChangeGraphServlet.class);
         bind(ChangeGraphServlet.class).in(Singleton.class);
     }
+
+    @Provides
+    @Singleton
+    ObjectMapper createObjectMapper() {
+        ObjectMapper objectMapper = new ObjectMapper();
+        objectMapper.setDateFormat(new SimpleDateFormat("YYYY-MM-dd'T'HH:mm")); // ISO8601 without time zone
+        objectMapper.registerModule(new JtsModule());
+
+        // Because VirtualEdgeIteratorState has getters which throw Exceptions.
+        // http://stackoverflow.com/questions/35359430/how-to-make-jackson-ignore-properties-if-the-getters-throw-exceptions
+        objectMapper.registerModule(new SimpleModule().setSerializerModifier(new BeanSerializerModifier() {
+            @Override
+            public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
+                return beanProperties.stream().map(bpw -> new BeanPropertyWriter(bpw) {
+                    @Override
+                    public void serializeAsField(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception {
+                        try {
+                            super.serializeAsField(bean, gen, prov);
+                        } catch (Exception e) {
+                            // Ignoring expected exception, see above.
+                        }
+                    }
+                }).collect(Collectors.toList());
+            }
+        }));
+        return objectMapper;
+    }
+
 }
diff --git a/web/src/main/java/com/graphhopper/http/GraphHopperWeb.java b/web/src/main/java/com/graphhopper/http/GraphHopperWeb.java
index 8d2f26495..b2d680cbd 100644
--- a/web/src/main/java/com/graphhopper/http/GraphHopperWeb.java
+++ b/web/src/main/java/com/graphhopper/http/GraphHopperWeb.java
@@ -17,29 +17,19 @@
  */
 package com.graphhopper.http;
 
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.graphhopper.GHRequest;
 import com.graphhopper.GHResponse;
 import com.graphhopper.GraphHopperAPI;
 import com.graphhopper.PathWrapper;
 import com.graphhopper.util.*;
-import com.graphhopper.util.exceptions.ConnectionNotFoundException;
-import com.graphhopper.util.exceptions.DetailedIllegalArgumentException;
-import com.graphhopper.util.exceptions.DetailedRuntimeException;
-import com.graphhopper.util.exceptions.PointNotFoundException;
-import com.graphhopper.util.exceptions.PointOutOfBoundsException;
+import com.graphhopper.util.exceptions.*;
 import com.graphhopper.util.shapes.GHPoint;
-import org.json.JSONArray;
-import org.json.JSONObject;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
 
-import org.json.JSONException;
+import java.util.*;
+import java.util.Map.Entry;
 
 /**
  * Main wrapper of the GraphHopper Directions API for a simple and efficient usage.
@@ -48,6 +38,7 @@ import org.json.JSONException;
  * @author Peter Karich
  */
 public class GraphHopperWeb implements GraphHopperAPI {
+    private ObjectMapper objectMapper;
     private final Set<String> ignoreSet;
     private Downloader downloader = new Downloader("GraphHopper Java Client");
     private String routeServiceUrl = "https://graphhopper.com/api/1/route";
@@ -59,7 +50,7 @@ public class GraphHopperWeb implements GraphHopperAPI {
 
     public GraphHopperWeb() {
         // some parameters are supported directly via Java API so ignore them when writing the getHints map
-        ignoreSet = new HashSet<String>();
+        ignoreSet = new HashSet<>();
         ignoreSet.add("calc_points");
         ignoreSet.add("calcpoints");
         ignoreSet.add("instructions");
@@ -76,41 +67,41 @@ public class GraphHopperWeb implements GraphHopperAPI {
         ignoreSet.add("points_encoded");
         ignoreSet.add("pointsencoded");
         ignoreSet.add("type");
+        objectMapper = new ObjectMapper();
     }
 
-    public static PathWrapper createPathWrapper(JSONObject path,
-                                                boolean tmpCalcPoints, boolean tmpInstructions,
-                                                boolean tmpElevation, boolean turnDescription) {
+    private PathWrapper createPathWrapper(JsonNode path,
+                                                 boolean tmpCalcPoints, boolean tmpInstructions,
+                                                 boolean tmpElevation, boolean turnDescription) {
         PathWrapper pathWrapper = new PathWrapper();
         pathWrapper.addErrors(readErrors(path));
         if (pathWrapper.hasErrors())
             return pathWrapper;
 
         if (path.has("snapped_waypoints")) {
-            String snappedPointStr = path.getString("snapped_waypoints");
+            String snappedPointStr = path.get("snapped_waypoints").asText();
             PointList snappedPoints = WebHelper.decodePolyline(snappedPointStr, 5, tmpElevation);
             pathWrapper.setWaypoints(snappedPoints);
         }
 
         if (tmpCalcPoints) {
-            String pointStr = path.getString("points");
+            String pointStr = path.get("points").asText();
             PointList pointList = WebHelper.decodePolyline(pointStr, 100, tmpElevation);
             pathWrapper.setPoints(pointList);
 
             if (tmpInstructions) {
-                JSONArray instrArr = path.getJSONArray("instructions");
+                JsonNode instrArr = path.get("instructions");
 
                 InstructionList il = new InstructionList(null);
                 int viaCount = 1;
-                for (int instrIndex = 0; instrIndex < instrArr.length(); instrIndex++) {
-                    JSONObject jsonObj = instrArr.getJSONObject(instrIndex);
-                    double instDist = jsonObj.getDouble("distance");
-                    String text = turnDescription ? jsonObj.getString("text") : jsonObj.getString("street_name");
-                    long instTime = jsonObj.getLong("time");
-                    int sign = jsonObj.getInt("sign");
-                    JSONArray iv = jsonObj.getJSONArray("interval");
-                    int from = iv.getInt(0);
-                    int to = iv.getInt(1);
+                for (JsonNode jsonObj : instrArr) {
+                    double instDist = jsonObj.get("distance").asDouble();
+                    String text = turnDescription ? jsonObj.get("text").asText() : jsonObj.get("street_name").asText();
+                    long instTime = jsonObj.get("time").asLong();
+                    int sign = jsonObj.get("sign").asInt();
+                    JsonNode iv = jsonObj.get("interval");
+                    int from = iv.get(0).asInt();
+                    int to = iv.get(1).asInt();
                     PointList instPL = new PointList(to - from, tmpElevation);
                     for (int j = from; j <= to; j++) {
                         instPL.add(pointList, j);
@@ -118,7 +109,7 @@ public class GraphHopperWeb implements GraphHopperAPI {
 
                     InstructionAnnotation ia = InstructionAnnotation.EMPTY;
                     if (jsonObj.has("annotation_importance") && jsonObj.has("annotation_text")) {
-                        ia = new InstructionAnnotation(jsonObj.getInt("annotation_importance"), jsonObj.getString("annotation_text"));
+                        ia = new InstructionAnnotation(jsonObj.get("annotation_importance").asInt(), jsonObj.get("annotation_text").asText());
                     }
 
                     Instruction instr;
@@ -126,17 +117,17 @@ public class GraphHopperWeb implements GraphHopperAPI {
                         RoundaboutInstruction ri = new RoundaboutInstruction(sign, text, ia, instPL);
 
                         if (jsonObj.has("exit_number")) {
-                            ri.setExitNumber(jsonObj.getInt("exit_number"));
+                            ri.setExitNumber(jsonObj.get("exit_number").asInt());
                         }
 
                         if (jsonObj.has("exited")) {
-                            if (jsonObj.getBoolean("exited"))
+                            if (jsonObj.get("exited").asBoolean())
                                 ri.setExited();
                         }
 
                         if (jsonObj.has("turn_angle")) {
                             // TODO provide setTurnAngle setter
-                            double angle = jsonObj.getDouble("turn_angle");
+                            double angle = jsonObj.get("turn_angle").asDouble();
                             ri.setDirOfRotation(angle);
                             ri.setRadian((angle < 0 ? -Math.PI : Math.PI) - angle);
                         }
@@ -167,62 +158,38 @@ public class GraphHopperWeb implements GraphHopperAPI {
             }
         }
 
-        double distance = path.getDouble("distance");
-        long time = path.getLong("time");
+        double distance = path.get("distance").asDouble();
+        long time = path.get("time").asLong();
         pathWrapper.setDistance(distance).setTime(time);
         return pathWrapper;
     }
 
     // Credits to: http://stackoverflow.com/a/24012023/194609
-    private static Map<String, Object> toMap(JSONObject object) throws JSONException {
-        Map<String, Object> map = new HashMap<>(object.keySet().size());
-        for (String key : object.keySet()) {
-            Object value = object.get(key);
-            if (value instanceof JSONArray) {
-                value = toList((JSONArray) value);
-            } else if (value instanceof JSONObject) {
-                value = toMap((JSONObject) value);
-            }
-            map.put(key, value);
-        }
-        return map;
-    }
-
-    private static List<Object> toList(JSONArray array) throws JSONException {
-        List<Object> list = new ArrayList<>();
-        for (Object value : array) {
-            if (value instanceof JSONArray) {
-                value = toList((JSONArray) value);
-            } else if (value instanceof JSONObject) {
-                value = toMap((JSONObject) value);
-            }
-            list.add(value);
-        }
-        return list;
+    private Map<String, Object> toMap(JsonNode object) {
+        return objectMapper.convertValue(object, new TypeReference<Map<String, Object>>() {});
     }
 
-    public static List<Throwable> readErrors(JSONObject json) {
+    public List<Throwable> readErrors(JsonNode json) {
         List<Throwable> errors = new ArrayList<>();
-        JSONArray errorJson;
+        JsonNode errorJson;
 
         if (json.has("message")) {
             if (json.has("hints")) {
-                errorJson = json.getJSONArray("hints");
+                errorJson = json.get("hints");
             } else {
                 // should not happen
-                errors.add(new RuntimeException(json.getString("message")));
+                errors.add(new RuntimeException(json.get("message").asText()));
                 return errors;
             }
         } else
             return errors;
 
-        for (int i = 0; i < errorJson.length(); i++) {
-            JSONObject error = errorJson.getJSONObject(i);
+        for (JsonNode error : errorJson) {
             String exClass = "";
             if (error.has("details"))
-                exClass = error.getString("details");
+                exClass = error.get("details").asText();
 
-            String exMessage = error.getString("message");
+            String exMessage = error.get("message").asText();
 
             if (exClass.equals(UnsupportedOperationException.class.getName()))
                 errors.add(new UnsupportedOperationException(exMessage));
@@ -235,10 +202,10 @@ public class GraphHopperWeb implements GraphHopperAPI {
             else if (exClass.equals(ConnectionNotFoundException.class.getName())) {
                 errors.add(new ConnectionNotFoundException(exMessage, toMap(error)));
             } else if (exClass.equals(PointNotFoundException.class.getName())) {
-                int pointIndex = error.getInt("point_index");
+                int pointIndex = error.get("point_index").asInt();
                 errors.add(new PointNotFoundException(exMessage, pointIndex));
             } else if (exClass.equals(PointOutOfBoundsException.class.getName())) {
-                int pointIndex = error.getInt("point_index");
+                int pointIndex = error.get("point_index").asInt();
                 errors.add(new PointOutOfBoundsException(exMessage, pointIndex));
             } else if (exClass.isEmpty())
                 errors.add(new DetailedRuntimeException(exMessage, toMap(error)));
@@ -247,7 +214,7 @@ public class GraphHopperWeb implements GraphHopperAPI {
         }
 
         if (json.has("message") && errors.isEmpty())
-            errors.add(new RuntimeException(json.getString("message")));
+            errors.add(new RuntimeException(json.get("message").asText()));
 
         return errors;
     }
@@ -334,16 +301,15 @@ public class GraphHopperWeb implements GraphHopperAPI {
             }
 
             String str = downloader.downloadAsString(url, true);
-            JSONObject json = new JSONObject(str);
+            JsonNode json = objectMapper.reader().readTree(str);
 
             GHResponse res = new GHResponse();
             res.addErrors(readErrors(json));
             if (res.hasErrors())
                 return res;
 
-            JSONArray paths = json.getJSONArray("paths");
-            for (int index = 0; index < paths.length(); index++) {
-                JSONObject path = paths.getJSONObject(index);
+            JsonNode paths = json.get("paths");
+            for (JsonNode path : paths) {
                 PathWrapper altRsp = createPathWrapper(path, tmpCalcPoints, tmpInstructions, tmpElevation, tmpTurnDescription);
                 res.add(altRsp);
             }
diff --git a/web/src/main/java/com/graphhopper/http/I18NServlet.java b/web/src/main/java/com/graphhopper/http/I18NServlet.java
index f8b655333..faf25beee 100644
--- a/web/src/main/java/com/graphhopper/http/I18NServlet.java
+++ b/web/src/main/java/com/graphhopper/http/I18NServlet.java
@@ -17,10 +17,10 @@
  */
 package com.graphhopper.http;
 
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.graphhopper.util.Helper;
 import com.graphhopper.util.Translation;
 import com.graphhopper.util.TranslationMap;
-import org.json.JSONObject;
 
 import javax.inject.Inject;
 import javax.servlet.ServletException;
@@ -51,12 +51,12 @@ public class I18NServlet extends GHBaseServlet {
         }
 
         Translation tr = map.get(locale);
-        JSONObject json = new JSONObject();
+        ObjectNode json = jsonNodeFactory.objectNode();
         if (tr != null && !Locale.US.equals(tr.getLocale()))
-            json.put("default", tr.asMap());
+            json.putPOJO("default", tr.asMap());
 
-        json.put("locale", locale.toString());
-        json.put("en", map.get("en").asMap());
+        json.put("locale", locale);
+        json.putPOJO("en", map.get("en").asMap());
         writeJson(req, res, json);
     }
 }
diff --git a/web/src/main/java/com/graphhopper/http/InfoServlet.java b/web/src/main/java/com/graphhopper/http/InfoServlet.java
index b8043b5f7..b2e24cae0 100644
--- a/web/src/main/java/com/graphhopper/http/InfoServlet.java
+++ b/web/src/main/java/com/graphhopper/http/InfoServlet.java
@@ -17,13 +17,14 @@
  */
 package com.graphhopper.http;
 
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.graphhopper.storage.GraphHopperStorage;
 import com.graphhopper.storage.StorableProperties;
 import com.graphhopper.util.Constants;
 import com.graphhopper.util.Helper;
 import com.graphhopper.util.Parameters;
 import com.graphhopper.util.shapes.BBox;
-import org.json.JSONObject;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -44,7 +45,6 @@ public class InfoServlet extends GHBaseServlet {
     @Named("hasElevation")
     private boolean hasElevation;
 
-
     @Override
     public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
         BBox bb = storage.getBounds();
@@ -54,18 +54,17 @@ public class InfoServlet extends GHBaseServlet {
         list.add(bb.maxLon);
         list.add(bb.maxLat);
 
-        JSONObject json = new JSONObject();
-        json.put("bbox", list);
+        final JsonNodeFactory jsonNodeFactory = new JsonNodeFactory(false);
+        final ObjectNode json = jsonNodeFactory.objectNode();
+        json.putPOJO("bbox", list);
 
         String[] vehicles = storage.getEncodingManager().toString().split(",");
-        json.put("supported_vehicles", vehicles);
-        JSONObject features = new JSONObject();
+        json.putPOJO("supported_vehicles", vehicles);
+        ObjectNode features = json.putObject("features");
         for (String v : vehicles) {
-            JSONObject perVehicleJson = new JSONObject();
+            ObjectNode perVehicleJson = features.putObject(v);
             perVehicleJson.put("elevation", hasElevation);
-            features.put(v, perVehicleJson);
         }
-        json.put("features", features);
 
         json.put("version", Constants.VERSION);
         json.put("build_date", Constants.BUILD_DATE);
diff --git a/web/src/main/java/com/graphhopper/http/InvalidRequestServlet.java b/web/src/main/java/com/graphhopper/http/InvalidRequestServlet.java
index a047a3748..c7ef8af1c 100644
--- a/web/src/main/java/com/graphhopper/http/InvalidRequestServlet.java
+++ b/web/src/main/java/com/graphhopper/http/InvalidRequestServlet.java
@@ -15,7 +15,7 @@
  */
 package com.graphhopper.http;
 
-import org.json.JSONObject;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
@@ -25,7 +25,7 @@ import java.io.IOException;
 public class InvalidRequestServlet extends GHBaseServlet {
     @Override
     protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
-        JSONObject json = new JSONObject();
+        ObjectNode json = jsonNodeFactory.objectNode();
         json.put("message", "Not found");
         writeJsonError(res, HttpServletResponse.SC_NOT_FOUND, json);
     }
diff --git a/web/src/main/java/com/graphhopper/http/NearestServlet.java b/web/src/main/java/com/graphhopper/http/NearestServlet.java
index e1332f6a6..a9f7fd8f0 100644
--- a/web/src/main/java/com/graphhopper/http/NearestServlet.java
+++ b/web/src/main/java/com/graphhopper/http/NearestServlet.java
@@ -17,6 +17,8 @@
  */
 package com.graphhopper.http;
 
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.graphhopper.routing.util.EdgeFilter;
 import com.graphhopper.storage.index.LocationIndex;
 import com.graphhopper.storage.index.QueryResult;
@@ -24,8 +26,6 @@ import com.graphhopper.util.DistanceCalc;
 import com.graphhopper.util.Helper;
 import com.graphhopper.util.shapes.GHPoint;
 import com.graphhopper.util.shapes.GHPoint3D;
-import org.json.JSONArray;
-import org.json.JSONObject;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -50,7 +50,7 @@ public class NearestServlet extends GHBaseServlet {
         String pointStr = getParam(httpReq, "point", null);
         boolean enabledElevation = getBooleanParam(httpReq, "elevation", false);
 
-        JSONObject result = new JSONObject();
+        ObjectNode result = jsonNodeFactory.objectNode();
         if (pointStr != null && !pointStr.equalsIgnoreCase("")) {
             GHPoint place = GHPoint.parse(pointStr);
             QueryResult qr = index.findClosest(place.lat, place.lon, EdgeFilter.ALL_EDGES);
@@ -61,14 +61,12 @@ public class NearestServlet extends GHBaseServlet {
                 GHPoint3D snappedPoint = qr.getSnappedPoint();
                 result.put("type", "Point");
 
-                JSONArray coord = new JSONArray();
-                coord.put(snappedPoint.lon);
-                coord.put(snappedPoint.lat);
+                ArrayNode coord = result.putArray("coordinates");
+                coord.add(snappedPoint.lon);
+                coord.add(snappedPoint.lat);
 
                 if (hasElevation && enabledElevation)
-                    coord.put(snappedPoint.ele);
-
-                result.put("coordinates", coord);
+                    coord.add(snappedPoint.ele);
 
                 // Distance from input to snapped point in meters
                 result.put("distance", calc.calcDist(place.lat, place.lon, snappedPoint.lat, snappedPoint.lon));
diff --git a/web/src/main/java/com/graphhopper/http/SimpleRouteSerializer.java b/web/src/main/java/com/graphhopper/http/SimpleRouteSerializer.java
index c87ce9629..fe11f4415 100644
--- a/web/src/main/java/com/graphhopper/http/SimpleRouteSerializer.java
+++ b/web/src/main/java/com/graphhopper/http/SimpleRouteSerializer.java
@@ -17,16 +17,6 @@
  */
 package com.graphhopper.http;
 
-import com.bedatadriven.jackson.datatype.jts.JtsModule;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.BeanDescription;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationConfig;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
-import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
 import com.graphhopper.GHResponse;
 import com.graphhopper.PathWrapper;
 import com.graphhopper.util.Helper;
@@ -36,40 +26,16 @@ import com.graphhopper.util.exceptions.GHException;
 import com.graphhopper.util.shapes.BBox;
 
 import java.text.NumberFormat;
-import java.text.SimpleDateFormat;
 import java.util.*;
-import java.util.stream.Collectors;
 
 /**
  * @author Peter Karich
  */
 public class SimpleRouteSerializer implements RouteSerializer {
     private final BBox maxBounds;
-    private final ObjectMapper objectMapper = new ObjectMapper();
 
     public SimpleRouteSerializer(BBox maxBounds) {
         this.maxBounds = maxBounds;
-        this.objectMapper.setDateFormat(new SimpleDateFormat("YYYY-MM-dd'T'HH:mm")); // ISO8601 without time zone
-        this.objectMapper.registerModule(new JtsModule());
-
-        // Because VirtualEdgeIteratorState has getters which throw Exceptions.
-        // http://stackoverflow.com/questions/35359430/how-to-make-jackson-ignore-properties-if-the-getters-throw-exceptions
-        this.objectMapper.registerModule(new SimpleModule().setSerializerModifier(new BeanSerializerModifier() {
-            @Override
-            public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
-                return beanProperties.stream().map(bpw -> new BeanPropertyWriter(bpw) {
-                    @Override
-                    public void serializeAsField(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception {
-                        try {
-                            super.serializeAsField(bean, gen, prov);
-                        } catch (Exception e) {
-                            // Ignoring expected exception, see above.
-                        }
-                    }
-                }).collect(Collectors.toList());
-            }
-        }));
-
     }
 
     private String getMessage(Throwable t) {
@@ -132,7 +98,7 @@ public class SimpleRouteSerializer implements RouteSerializer {
                         jsonPath.put("instructions", instructions.createJson());
                     }
 
-                    jsonPath.put("legs", objectMapper.convertValue(ar.getLegs(), new TypeReference<List<Map<String, Object>>>() {}));
+                    jsonPath.put("legs", ar.getLegs());
 
                     jsonPath.put("ascend", ar.getAscend());
                     jsonPath.put("descend", ar.getDescend());
diff --git a/web/src/main/java/com/graphhopper/http/WebHelper.java b/web/src/main/java/com/graphhopper/http/WebHelper.java
index 4bc566a7b..656aeae1c 100644
--- a/web/src/main/java/com/graphhopper/http/WebHelper.java
+++ b/web/src/main/java/com/graphhopper/http/WebHelper.java
@@ -18,9 +18,6 @@
 package com.graphhopper.http;
 
 import com.graphhopper.util.PointList;
-import com.graphhopper.util.shapes.GHPoint;
-import com.graphhopper.util.shapes.GHPoint3D;
-import org.json.JSONArray;
 
 import java.io.BufferedInputStream;
 import java.io.ByteArrayOutputStream;
@@ -151,11 +148,4 @@ public class WebHelper {
         }
     }
 
-    public static GHPoint toGHPoint(JSONArray point) {
-        if (point.length() == 3 && !Double.isNaN(point.getDouble(2))) {
-            return new GHPoint3D(point.getDouble(1), point.getDouble(0), point.getDouble(2));
-        }
-
-        return new GHPoint(point.getDouble(1), point.getDouble(0));
-    }
 }


Test patch:
diff --git a/core/src/test/java/com/graphhopper/util/InstructionListTest.java b/core/src/test/java/com/graphhopper/util/InstructionListTest.java
index 0e6507835..b7c8d0b09 100644
--- a/core/src/test/java/com/graphhopper/util/InstructionListTest.java
+++ b/core/src/test/java/com/graphhopper/util/InstructionListTest.java
@@ -17,6 +17,8 @@
  */
 package com.graphhopper.util;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.graphhopper.reader.ReaderWay;
 import com.graphhopper.routing.Dijkstra;
 import com.graphhopper.routing.Path;
@@ -28,7 +30,6 @@ import com.graphhopper.routing.weighting.ShortestWeighting;
 import com.graphhopper.storage.Graph;
 import com.graphhopper.storage.GraphBuilder;
 import com.graphhopper.storage.NodeAccess;
-import org.json.JSONObject;
 import org.junit.Before;
 import org.junit.Test;
 import org.xml.sax.SAXException;
@@ -352,7 +353,15 @@ public class InstructionListTest {
         assertEquals(-1, (Double) json.get("turn_angle"), 0.01);
         assertEquals("2", json.get("exit_number").toString());
         // assert that a valid JSON object can be written
-        assertNotNull(new JSONObject(json).toString());
+        assertNotNull(write(json));
+    }
+
+    private String write(Map<String, Object> json) {
+        try {
+            return new ObjectMapper().writeValueAsString(json);
+        } catch (JsonProcessingException e) {
+            throw new RuntimeException(e);
+        }
     }
 
     // Roundabout with unknown dir of rotation
@@ -375,7 +384,7 @@ public class InstructionListTest {
         assertEquals("At roundabout, take exit 2 onto streetname", json.get("text").toString());
         assertNull(json.get("turn_angle"));
         // assert that a valid JSON object can be written
-        assertNotNull(new JSONObject(json).toString());
+        assertNotNull(write(json));
     }
 
     @Test
diff --git a/web/src/test/java/com/graphhopper/http/BaseServletTester.java b/web/src/test/java/com/graphhopper/http/BaseServletTester.java
index 20f448596..7e561d98a 100644
--- a/web/src/test/java/com/graphhopper/http/BaseServletTester.java
+++ b/web/src/test/java/com/graphhopper/http/BaseServletTester.java
@@ -17,29 +17,23 @@
  */
 package com.graphhopper.http;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Module;
 import com.graphhopper.util.CmdArgs;
 import com.graphhopper.util.Downloader;
 import com.graphhopper.util.Helper;
-
-import java.io.IOException;
-
-import org.json.JSONObject;
+import okhttp3.*;
+import org.eclipse.jetty.http.HttpStatus;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
 import java.net.HttpURLConnection;
 import java.util.concurrent.TimeUnit;
 
-import okhttp3.MediaType;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-import org.eclipse.jetty.http.HttpStatus;
-
 import static org.junit.Assert.assertEquals;
 
 /**
@@ -53,6 +47,7 @@ public class BaseServletTester {
     protected static int port;
     private static GHServer server;
     protected Injector injector;
+    private ObjectMapper objectMapper = new ObjectMapper();
 
     public static void shutdownJetty(boolean force) {
         // this is too slow so allow force == false. Then on setUpJetty a new server is created on a different port
@@ -136,11 +131,11 @@ public class BaseServletTester {
         return Helper.isToString(downloader.fetch(conn, true));
     }
 
-    protected JSONObject query(String query, int code) throws Exception {
-        return new JSONObject(queryString(query, code));
+    protected JsonNode query(String query, int code) throws Exception {
+        return objectMapper.readTree(queryString(query, code));
     }
 
-    protected JSONObject nearestQuery(String query) throws Exception {
+    protected JsonNode nearestQuery(String query) throws Exception {
         String resQuery = "";
         for (String q : query.split("\\&")) {
             int index = q.indexOf("=");
@@ -153,7 +148,7 @@ public class BaseServletTester {
         }
         String url = getTestNearestAPIUrl() + "?" + resQuery;
         Downloader downloader = new Downloader("web integration tester");
-        return new JSONObject(downloader.downloadAsString(url, true));
+        return objectMapper.readTree(downloader.downloadAsString(url, true));
     }
 
     protected String post(String path, int expectedStatusCode, String xmlOrJson) throws IOException {
diff --git a/web/src/test/java/com/graphhopper/http/ChangeGraphServletIT.java b/web/src/test/java/com/graphhopper/http/ChangeGraphServletIT.java
index 91b9ecd6e..8cbe1076f 100644
--- a/web/src/test/java/com/graphhopper/http/ChangeGraphServletIT.java
+++ b/web/src/test/java/com/graphhopper/http/ChangeGraphServletIT.java
@@ -17,10 +17,11 @@
  */
 package com.graphhopper.http;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.graphhopper.util.CmdArgs;
 import com.graphhopper.util.Helper;
 import com.graphhopper.util.Parameters;
-import org.json.JSONObject;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.Test;
@@ -53,12 +54,13 @@ public class ChangeGraphServletIT extends BaseServletTester {
 
     @Test
     public void testBlockAccessViaPoint() throws Exception {
-        JSONObject json = query("point=42.531453,1.518946&point=42.511178,1.54006", 200);
-        JSONObject infoJson = json.getJSONObject("info");
+        final ObjectMapper objectMapper = new ObjectMapper();
+        JsonNode json = query("point=42.531453,1.518946&point=42.511178,1.54006", 200);
+        JsonNode infoJson = json.get("info");
         assertFalse(infoJson.has("errors"));
-        JSONObject path = json.getJSONArray("paths").getJSONObject(0);
+        JsonNode path = json.get("paths").get(0);
         // System.out.println("\n\n1\n" + path);
-        double distance = path.getDouble("distance");
+        double distance = path.get("distance").asDouble();
         assertTrue("distance wasn't correct:" + distance, distance > 3000);
         assertTrue("distance wasn't correct:" + distance, distance < 3500);
 
@@ -76,18 +78,18 @@ public class ChangeGraphServletIT extends BaseServletTester {
                 + "    'access': false"
                 + "  }}]}".replaceAll("'", "\"");
         String res = post("/change", 200, geoJson);
-        JSONObject jsonObj = new JSONObject(res);
-        assertEquals(1, jsonObj.getInt("updates"));
+        JsonNode jsonObj = objectMapper.readTree(res);
+        assertEquals(1, jsonObj.get("updates").asInt());
 
         // route around blocked road => longer
         json = query("point=42.531453,1.518946&point=42.511178,1.54006", 200);
-        infoJson = json.getJSONObject("info");
+        infoJson = json.get("info");
         assertFalse(infoJson.has("errors"));
-        path = json.getJSONArray("paths").getJSONObject(0);
+        path = json.get("paths").get(0);
 
         // System.out.println("\n\n2\n" + path);
 
-        distance = path.getDouble("distance");
+        distance = path.get("distance").asDouble();
         assertTrue("distance wasn't correct:" + distance, distance > 5300);
         assertTrue("distance wasn't correct:" + distance, distance < 5800);
     }
diff --git a/web/src/test/java/com/graphhopper/http/GraphHopperServletIT.java b/web/src/test/java/com/graphhopper/http/GraphHopperServletIT.java
index 10df94586..9edb2417d 100644
--- a/web/src/test/java/com/graphhopper/http/GraphHopperServletIT.java
+++ b/web/src/test/java/com/graphhopper/http/GraphHopperServletIT.java
@@ -17,23 +17,21 @@
  */
 package com.graphhopper.http;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.graphhopper.GHRequest;
 import com.graphhopper.GHResponse;
 import com.graphhopper.GraphHopperAPI;
 import com.graphhopper.PathWrapper;
 import com.graphhopper.util.CmdArgs;
 import com.graphhopper.util.Helper;
-import com.graphhopper.util.TranslationMap;
 import com.graphhopper.util.exceptions.PointOutOfBoundsException;
 import com.graphhopper.util.shapes.GHPoint;
-import org.json.JSONObject;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.Test;
 
 import java.io.File;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 
 import static org.junit.Assert.*;
@@ -61,11 +59,11 @@ public class GraphHopperServletIT extends BaseServletTester {
 
     @Test
     public void testBasicQuery() throws Exception {
-        JSONObject json = query("point=42.554851,1.536198&point=42.510071,1.548128", 200);
-        JSONObject infoJson = json.getJSONObject("info");
+        JsonNode json = query("point=42.554851,1.536198&point=42.510071,1.548128", 200);
+        JsonNode infoJson = json.get("info");
         assertFalse(infoJson.has("errors"));
-        JSONObject path = json.getJSONArray("paths").getJSONObject(0);
-        double distance = path.getDouble("distance");
+        JsonNode path = json.get("paths").get(0);
+        double distance = path.get("distance").asDouble();
         assertTrue("distance wasn't correct:" + distance, distance > 9000);
         assertTrue("distance wasn't correct:" + distance, distance < 9500);
     }
@@ -73,11 +71,11 @@ public class GraphHopperServletIT extends BaseServletTester {
     @Test
     public void testQueryWithDirections() throws Exception {
         // Note, in general specifying directions does not work with CH, but this is an example where it works
-        JSONObject json = query("point=42.496696,1.499323&point=42.497257,1.501501&heading=240&heading=240&ch.force_heading=true", 200);
-        JSONObject infoJson = json.getJSONObject("info");
+        JsonNode json = query("point=42.496696,1.499323&point=42.497257,1.501501&heading=240&heading=240&ch.force_heading=true", 200);
+        JsonNode infoJson = json.get("info");
         assertFalse(infoJson.has("errors"));
-        JSONObject path = json.getJSONArray("paths").getJSONObject(0);
-        double distance = path.getDouble("distance");
+        JsonNode path = json.get("paths").get(0);
+        double distance = path.get("distance").asDouble();
         assertTrue("distance wasn't correct:" + distance, distance > 960);
         assertTrue("distance wasn't correct:" + distance, distance < 970);
     }
@@ -85,29 +83,29 @@ public class GraphHopperServletIT extends BaseServletTester {
     @Test
     public void testQueryWithStraightVia() throws Exception {
         // Note, in general specifying straightvia does not work with CH, but this is an example where it works
-        JSONObject json = query(
+        JsonNode json = query(
                 "point=42.534133,1.581473&point=42.534781,1.582149&point=42.535042,1.582514&pass_through=true", 200);
-        JSONObject infoJson = json.getJSONObject("info");
+        JsonNode infoJson = json.get("info");
         assertFalse(infoJson.has("errors"));
-        JSONObject path = json.getJSONArray("paths").getJSONObject(0);
-        double distance = path.getDouble("distance");
+        JsonNode path = json.get("paths").get(0);
+        double distance = path.get("distance").asDouble();
         assertTrue("distance wasn't correct:" + distance, distance > 320);
         assertTrue("distance wasn't correct:" + distance, distance < 325);
     }
 
     @Test
     public void testJsonRounding() throws Exception {
-        JSONObject json = query("point=42.554851234,1.536198&point=42.510071,1.548128&points_encoded=false", 200);
-        JSONObject cson = json.getJSONArray("paths").getJSONObject(0).getJSONObject("points");
+        JsonNode json = query("point=42.554851234,1.536198&point=42.510071,1.548128&points_encoded=false", 200);
+        JsonNode cson = json.get("paths").get(0).get("points");
         assertTrue("unexpected precision!", cson.toString().contains("[1.536374,42.554839]"));
     }
 
     @Test
     public void testFailIfElevationRequestedButNotIncluded() throws Exception {
-        JSONObject json = query("point=42.554851234,1.536198&point=42.510071,1.548128&points_encoded=false&elevation=true", 400);
+        JsonNode json = query("point=42.554851234,1.536198&point=42.510071,1.548128&points_encoded=false&elevation=true", 400);
         assertTrue(json.has("message"));
-        assertEquals("Elevation not supported!", json.get("message"));
-        assertEquals("Elevation not supported!", json.getJSONArray("hints").getJSONObject(0).getString("message"));
+        assertEquals("Elevation not supported!", json.get("message").asText());
+        assertEquals("Elevation not supported!", json.get("hints").get(0).get("message").asText());
     }
 
     @Test
@@ -219,9 +217,9 @@ public class GraphHopperServletIT extends BaseServletTester {
 
     @Test
     public void testUndefinedPointHeading() throws Exception {
-        JSONObject json = query("point=undefined&heading=0", 400);
-        assertEquals("You have to pass at least one point", json.get("message"));
+        JsonNode json = query("point=undefined&heading=0", 400);
+        assertEquals("You have to pass at least one point", json.get("message").asText());
         json = query("point=42.554851,1.536198&point=undefined&heading=0&heading=0", 400);
-        assertEquals("The number of 'heading' parameters must be <= 1 or equal to the number of points (1)", json.get("message"));
+        assertEquals("The number of 'heading' parameters must be <= 1 or equal to the number of points (1)", json.get("message").asText());
     }
 }
diff --git a/web/src/test/java/com/graphhopper/http/GraphHopperServletWithEleIT.java b/web/src/test/java/com/graphhopper/http/GraphHopperServletWithEleIT.java
index c868d6824..c97b1735d 100644
--- a/web/src/test/java/com/graphhopper/http/GraphHopperServletWithEleIT.java
+++ b/web/src/test/java/com/graphhopper/http/GraphHopperServletWithEleIT.java
@@ -17,10 +17,10 @@
  */
 package com.graphhopper.http;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.graphhopper.util.CmdArgs;
 import com.graphhopper.util.Helper;
 import com.graphhopper.util.Parameters;
-import org.json.JSONObject;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.Test;
@@ -56,41 +56,41 @@ public class GraphHopperServletWithEleIT extends BaseServletTester {
 
     @Test
     public void testElevation() throws Exception {
-        JSONObject json = query("point=43.730864,7.420771&point=43.727687,7.418737&points_encoded=false&elevation=true", 200);
-        JSONObject infoJson = json.getJSONObject("info");
+        JsonNode json = query("point=43.730864,7.420771&point=43.727687,7.418737&points_encoded=false&elevation=true", 200);
+        JsonNode infoJson = json.get("info");
         assertFalse(infoJson.has("errors"));
-        JSONObject path = json.getJSONArray("paths").getJSONObject(0);
-        double distance = path.getDouble("distance");
+        JsonNode path = json.get("paths").get(0);
+        double distance = path.get("distance").asDouble();
         assertTrue("distance wasn't correct:" + distance, distance > 2500);
         assertTrue("distance wasn't correct:" + distance, distance < 2700);
 
-        JSONObject cson = path.getJSONObject("points");
-        assertTrue("no elevation?", cson.toString().contains("[7.421392,43.7307,66]"));
+        JsonNode cson = path.get("points");
+        assertTrue("no elevation?", cson.toString().contains("[7.421392,43.7307,66.0]"));
 
         // Although we include elevation DO NOT include it in the bbox as bbox.toGeoJSON messes up when reading
         // or reading with and without elevation would be too complex for the client with no real use
-        assertEquals(4, path.getJSONArray("bbox").length());
+        assertEquals(4, path.get("bbox").size());
     }
 
     @Test
     public void testNoElevation() throws Exception {
         // default is elevation=false
-        JSONObject json = query("point=43.730864,7.420771&point=43.727687,7.418737&points_encoded=false", 200);
-        JSONObject infoJson = json.getJSONObject("info");
+        JsonNode json = query("point=43.730864,7.420771&point=43.727687,7.418737&points_encoded=false", 200);
+        JsonNode infoJson = json.get("info");
         assertFalse(infoJson.has("errors"));
-        JSONObject path = json.getJSONArray("paths").getJSONObject(0);
-        double distance = path.getDouble("distance");
+        JsonNode path = json.get("paths").get(0);
+        double distance = path.get("distance").asDouble();
         assertTrue("distance wasn't correct:" + distance, distance > 2500);
         assertTrue("distance wasn't correct:" + distance, distance < 2700);
-        JSONObject cson = path.getJSONObject("points");
+        JsonNode cson = path.get("points");
         assertTrue("Elevation should not be included!", cson.toString().contains("[7.421392,43.7307]"));
 
         // disable elevation
         json = query("point=43.730864,7.420771&point=43.727687,7.418737&points_encoded=false&elevation=false", 200);
-        infoJson = json.getJSONObject("info");
+        infoJson = json.get("info");
         assertFalse(infoJson.has("errors"));
-        path = json.getJSONArray("paths").getJSONObject(0);
-        cson = path.getJSONObject("points");
+        path = json.get("paths").get(0);
+        cson = path.get("points");
         assertTrue("Elevation should not be included!", cson.toString().contains("[7.421392,43.7307]"));
     }
 }
diff --git a/web/src/test/java/com/graphhopper/http/NearestServletIT.java b/web/src/test/java/com/graphhopper/http/NearestServletIT.java
index 1cdd7c6f5..5e60eba80 100644
--- a/web/src/test/java/com/graphhopper/http/NearestServletIT.java
+++ b/web/src/test/java/com/graphhopper/http/NearestServletIT.java
@@ -17,10 +17,10 @@
  */
 package com.graphhopper.http;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.graphhopper.util.CmdArgs;
 import com.graphhopper.util.Helper;
-import org.json.JSONArray;
-import org.json.JSONObject;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.Test;
@@ -53,12 +53,12 @@ public class NearestServletIT extends BaseServletTester {
 
     @Test
     public void testBasicNearestQuery() throws Exception {
-        JSONObject json = nearestQuery("point=42.554851,1.536198");
+        JsonNode json = nearestQuery("point=42.554851,1.536198");
         assertFalse(json.has("error"));
-        JSONArray point = json.getJSONArray("coordinates");
-        assertTrue("returned point is not 2D: " + point, point.length() == 2);
-        double lon = point.getDouble(0);
-        double lat = point.getDouble(1);
+        ArrayNode point = (ArrayNode) json.get("coordinates");
+        assertTrue("returned point is not 2D: " + point, point.size() == 2);
+        double lon = point.get(0).asDouble();
+        double lat = point.get(1).asDouble();
         assertTrue("nearest point wasn't correct: lat=" + lat + ", lon=" + lon, lat == 42.55483907636756 && lon == 1.5363742288086868);
     }
 }
diff --git a/web/src/test/java/com/graphhopper/http/NearestServletWithEleIT.java b/web/src/test/java/com/graphhopper/http/NearestServletWithEleIT.java
index 2c3f03eb9..a3ef83aca 100644
--- a/web/src/test/java/com/graphhopper/http/NearestServletWithEleIT.java
+++ b/web/src/test/java/com/graphhopper/http/NearestServletWithEleIT.java
@@ -17,11 +17,11 @@
  */
 package com.graphhopper.http;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.graphhopper.util.CmdArgs;
 import com.graphhopper.util.Helper;
 import com.graphhopper.util.Parameters;
-import org.json.JSONArray;
-import org.json.JSONObject;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.Test;
@@ -58,33 +58,33 @@ public class NearestServletWithEleIT extends BaseServletTester {
 
     @Test
     public void testWithEleQuery() throws Exception {
-        JSONObject json = nearestQuery("point=43.730864,7.420771&elevation=true");
+        JsonNode json = nearestQuery("point=43.730864,7.420771&elevation=true");
         assertFalse(json.has("error"));
-        JSONArray point = json.getJSONArray("coordinates");
-        assertTrue("returned point is not 3D: " + point, point.length() == 3);
-        double lon = point.getDouble(0);
-        double lat = point.getDouble(1);
-        double ele = point.getDouble(2);
+        ArrayNode point = (ArrayNode) json.get("coordinates");
+        assertTrue("returned point is not 3D: " + point, point.size() == 3);
+        double lon = point.get(0).asDouble();
+        double lat = point.get(1).asDouble();
+        double ele = point.get(2).asDouble();
         assertTrue("nearest point wasn't correct: lat=" + lat + ", lon=" + lon + ", ele=" + ele, lat == 43.73070006215647 && lon == 7.421392181993846 && ele == 66.0);
     }
 
     @Test
     public void testWithoutEleQuery() throws Exception {
-        JSONObject json = nearestQuery("point=43.730864,7.420771&elevation=false");
+        JsonNode json = nearestQuery("point=43.730864,7.420771&elevation=false");
         assertFalse(json.has("error"));
-        JSONArray point = json.getJSONArray("coordinates");
-        assertTrue("returned point is not 2D: " + point, point.length() == 2);
-        double lon = point.getDouble(0);
-        double lat = point.getDouble(1);
+        ArrayNode point = (ArrayNode) json.get("coordinates");
+        assertTrue("returned point is not 2D: " + point, point.size() == 2);
+        double lon = point.get(0).asDouble();
+        double lat = point.get(1).asDouble();
         assertTrue("nearest point wasn't correct: lat=" + lat + ", lon=" + lon, lat == 43.73070006215647 && lon == 7.421392181993846);
 
         // Default elevation is false        
         json = nearestQuery("point=43.730864,7.420771");
         assertFalse(json.has("error"));
-        point = json.getJSONArray("coordinates");
-        assertTrue("returned point is not 2D: " + point, point.length() == 2);
-        lon = point.getDouble(0);
-        lat = point.getDouble(1);
+        point = (ArrayNode) json.get("coordinates");
+        assertTrue("returned point is not 2D: " + point, point.size() == 2);
+        lon = point.get(0).asDouble();
+        lat = point.get(1).asDouble();
         assertTrue("nearest point wasn't correct: lat=" + lat + ", lon=" + lon, lat == 43.73070006215647 && lon == 7.421392181993846);
     }
 }