7

I am doing inverse geocoding using google geocoding APIs.

The results are returned in Json which I'm parsing in following manner -

Map<String, Object> parsedJson = new ObjectMapper().readValue(
                    response.getEntity(String.class),
                    new TypeReference<Map<String, Object>>() {
                    });
List<Object> results = (List<Object>) parsedJson.get("results");
// From first result get geometry details
Map<String, Object> geometry = (Map<String, Object>) ((Map<String, Object>) results
                    .get(0)).get("geometry");

Map<String, Object> location = (Map<String, Object>) geometry
                    .get("location");

Map<String, Double> coordinates = new HashMap<String, Double>();
coordinates.put("latitude", (Double) location.get("lat"));
coordinates.put("longitude", (Double) location.get("lng"));

Where response contains the Json returned from server.

Is it possible to get a direct reference to the location node without going through all this? E.g. is there something like -

new ObjectMapper().readValue(json).findNodeByName("lat").getFloatValue();

I have read the docs on JsonNode and Tree in Jackson Api but it seems they are useful only if you want to traverse the entire tree.

What would be the easiest way to fetch only a particular node?

Kshitiz Sharma
  • 17,947
  • 26
  • 98
  • 169

2 Answers2

9

+1 to Michael Hixson for pointing out the geocoding library.

But, after digging through the docs I've finally found the solution -

ObjectMapper mapper = new ObjectMapper(); 

JsonNode rootNode = mapper.readTree(mapper.getJsonFactory()
                        .createJsonParser(response.getEntity(String.class)));

rootNode.findValue("lat").getDoubleValue();
Kshitiz Sharma
  • 17,947
  • 26
  • 98
  • 169
1

I don't have an answer to your "how to find a node by name" question, but if you're just looking for a cleaner way of reading this data, then I'd recommend one of these approaches, in order:

A: Look for a pre-existing Java library for Google's Geocoding API. If right now you're making HTTP requests for this data in Java (using Apache HttpClient or something) and then parsing the JSON with Jackson, someone has probably done all that work before and packaged it up in a library. A quick search brought up this: http://code.google.com/p/geocoder-java/. You could get the first latitude value like this:

GeocodeResponse response = ... // Look at the example code on that site.
BigDecimal latitude = response.getResults().get(0).getGeometry().getLocation().getLat()

B: Create your own class hierarchy to represent the stuff you need, and then given Jackson the JSON and your root "response" class. I'm pretty sure it can build up instances of arbitrary classes from JSON. So something like this:

public class ResultSet {
  public List<Result> results;
}

public class Result {
  public Geometry geometry;
}

public class Geometry {
  public Location location;
}

public class Location {
  public double latitude;
  public double longitude;
}

String json = ... // The raw JSON you currently have.
Response response = new ObjectMapper().readValue(json, Response.class);
double latitude = response.results.get(0).geometry.location.latitude;
Michael Hixson
  • 1,250
  • 1
  • 10
  • 15
  • That addresses a single use case. Should I do the same when finding distance, getting directions, or performing address lookup? I'm trying to find something a little more generic. – Kshitiz Sharma Apr 26 '12 at 04:02
  • I would think that using that library I suggested would make all of your use cases easier. It gives you Java class representations of the geocoding JSON, which are going to be superior to Map no matter what properties you're trying to read. My second suggestion only included the specific properties you mentioned in your question, but that's just because I don't know the entire structure of that JSON offhand. Presumably you'd want to add properties and classes for everything in the JSON, not just lat/long. That effort is wasted though if you can just use the library. – Michael Hixson Apr 26 '12 at 04:27