1

Here's the problem:

public static <T> T execute(String query, Function<List<JsonNode>, T> function) {
        String jsonString = HttpRequest.get("http://overpass-api.de/api/interpreter", true, "data", query).body();

        List<JsonNode> list = toJsonNodeList(jsonString);

        T res = function.apply(list);

        return res;
    }

This method:

  1. perform a query that returns a json string
  2. transform that string into a JsonNode list
  3. finally, transform each JsonNode into a particular object

This is an example of function that convert each JsonNode into a geojson geometry and returns a geojson result set:

public class GeojsonMapper implements Function<List<JsonNode>, GeojsonSingleListResultSet> {

    @Override
    public GeojsonSingleListResultSet apply(List<JsonNode> list) {
        List<Element> elementList = list.parallelStream()
                .map(jsonNode -> {
                    String id = jsonNode.get("id").asText();
                    JsonNode tags = jsonNode.get("tags");
                    switch (jsonNode.get("type").asText()) {
                        case "node":
                            return new Point(jsonNode.get("lat").asDouble(), jsonNode.get("lon").asDouble(), id, tags);
                        case "way":
                            ArrayList<Point> points = new ArrayList<>();
                            JsonNode nodeList = jsonNode.get("geometry");
                            for (int j = 0; j < nodeList.size(); j++) {
                                JsonNode wayNode = nodeList.get(j);
                                points.add(j, new Point(wayNode.get("lat").asDouble(), wayNode.get("lon").asDouble()));
                            }
                            if (Polygon.isPolygon(points, tags)) {
                                return new Polygon(points, id, tags);
                            } else {
                                return new LineString(points, id, tags);
                            }
                        default:
                            Iterator<JsonNode> iterator = jsonNode.get("members").getElements();
                            List<List<Point>> rings = new ArrayList<>();
                            List<Point> ring = null;
                            while (iterator.hasNext()) {
                                JsonNode member = iterator.next();
                                JsonNode geometry = member.get("geometry");
                                ring = new ArrayList<>();
                                for (int ringIndex = 0; ringIndex < geometry.size(); ringIndex++) {
                                    JsonNode coordinates = geometry.get(ringIndex);
                                    ring.add(new Point(coordinates.get("lat").asDouble(), coordinates.get("lon").asDouble()));
                                }
                                rings.add(ring);
                            }
                            return new Multipolygon(Polygon.buildPolygons(rings), id, tags);
                    }
                })
                .collect(toList());

        return new GeojsonSingleListResultSet(elementList);
    }
}

Everything works well, but the toJsonNodeList() method is very slow in comparison to the method function.apply() that use a Stream. This is the toJsonNodeList()'s code:

private static List<JsonNode> toJsonNodeList(String s){

        ObjectMapper mapper = new ObjectMapper();
        List<JsonNode> list = new ArrayList<>();
        try{
        JsonNode resultSet = mapper.readTree(s).get("elements");
            Iterator<JsonNode> iterator = resultSet.getElements();
            while (iterator.hasNext()) {
                list.add(iterator.next());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return list;
    }

Is there a way to parse a json string using a parallelStream so as to extract each element and convert it to a JsonNode?

Kohei TAMURA
  • 4,970
  • 7
  • 25
  • 49
Cilla
  • 419
  • 5
  • 16
  • 5
    Be aware, [parallel streams are not a silver bullet](https://stackoverflow.com/questions/20375176/should-i-always-use-a-parallel-stream-when-possible) – Michael Jul 27 '17 at 17:08
  • 1
    I doubt it. You can't freely traverse a JSON tree until it's fully parsed. Subdividing the raw string will get you incomplete parts. – shmosel Jul 27 '17 at 17:15
  • There is too much code in this `map` method. Extract it into another method! – bartektartanus Aug 16 '17 at 15:17

0 Answers0