[SalesForce] Best way to parse JSON Response from Google Maps

I've written something that will get the longitude and latitude from a Google Geocode Callout.

The response we get from a generic callout looks like this:

{  
   results=(   {  
      address_components=(      {  
         long_name=1600,
         short_name=1600,
         types=(street_number 
    )
      },
      {  
         long_name=Amphitheatre Parkway,
         short_name=Amphitheatre Pkwy,
         types=(route)
      },
      {  
         long_name=Mountain View,
         short_name=Mountain View,
         types=(locality,
         political)
      },
      {  
         long_name=Santa Clara County,
         short_name=Santa Clara County,
         types=(administrative_area_level_2,
         political)
      },
      {  
         long_name=California,
         short_name=CA,
         types=(administrative_area_level_1,
         political)
      },
      {  
         long_name=United States,
         short_name=US,
         types=(country,
         political)
      },
      {  
         long_name=94043,
         short_name=94043,
         types=(postal_code)
      }      ),
      formatted_address=1600 Amphitheatre Pkwy,
      Mountain View,
      CA 94043,
      USA,
      geometry=      {  
         location=         {  
            lat=37.4223582,
            lng=-122.0844464
         },
         location_type=ROOFTOP,
         viewport=         {  
            northeast=            {  
               lat=37.4237071802915,
               lng=-122.0830974197085
            },
            southwest=            {  
               lat=37.4210092197085,
               lng=-122.0857953802915
            }
         }
      },
      place_id=ChIJ2eUgeAK6j4ARbn5u_wAGqWA,
      types=(street_address)
   }   ),
   status=OK
}

Specifically I'm interested in the following part:

  geometry=      {  
     location=         {  
        lat=37.4223582,
        lng=-122.0844464
     },

I've written a small HTTP class that parses through the response and puts the Longitude and Latitude into the Double lng, lat; variables that can then be processed into a Geolocation field.

Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=[MY_API_KEY]');
request.setMethod('GET');

HttpResponse response = http.send(request);

Double lat, lng;

if (response.getStatusCode() == 200) {
    JSONParser parser = JSON.createParser(response.getBody());

    while (parser.nextToken() != null) {
        if (parser.getCurrentToken() == JSONToken.FIELD_NAME && parser.getText() == 'geometry') {
            while (parser.nextToken() != JSONToken.END_OBJECT) {
                if (parser.getCurrentToken() == JSONToken.FIELD_NAME && parser.getText() == 'location') {
                    while (parser.nextToken() != JSONToken.END_OBJECT) {



                        if (parser.getCurrentToken() == JSONToken.FIELD_NAME && parser.getText() == 'lat') {
                            parser.nextToken();
                            lat = Double.valueOf(parser.getText());
                        }

                        if (parser.getCurrentToken() == JSONToken.FIELD_NAME && parser.getText() == 'lng') {
                            parser.nextToken();
                            lng = Double.valueOf(parser.getText());
                        }

                    }
                }
            }
        }
    }
}

System.debug('@@@@@ Lat: ' + lat);
System.debug('@@@@@ Lng: ' + lng);

Whilst this works, I'm not convinced I'm parsing it in the best way possible and that with so many while iterations and if statements that it couldn't be more efficient.

Is there a better way to parse through a JSON response, such as what Google provides from a Geocoder response?

Best Answer

Not a parser! Just deserialize:

public class Response { final Geometry geometry; }
public class Geometry { final Location location; }
public class Location { final Decimal latitude, longitude; }

Granted, your JSON payload is not valid as currently specified. The above would work though if your structure boils down to:

{
    "geometry": {
        "location": {
            "latitude": 0.0,
            "longitude": 0.0
        }
    },
    "other_properties": { /*values*/ }
}

If you want to copy the payload format listed here, the class would be slightly different.

JSON

{
   "results" : [
      {
         "address_components" : [...],
         "formatted_address" : "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA",
         "geometry" : {
            "location" : {
               "lat" : 37.4224764,
               "lng" : -122.0842499
            },
            "location_type" : "ROOFTOP",
            "viewport" : {
               "northeast" : {
                  "lat" : 37.4238253802915,
                  "lng" : -122.0829009197085
               },
               "southwest" : {
                  "lat" : 37.4211274197085,
                  "lng" : -122.0855988802915
               }
            }
         },
         "place_id" : "ChIJ2eUgeAK6j4ARbn5u_wAGqWA",
         "types" : [ "street_address" ]
      }
   ],
   "status" : "OK"
}

Apex

public class Response { final List<Result> results; }
public class Result { final Geometry geometry; }
public class Geometry { final Location location; }
public class Location { final Decimal latitude, longitude; }
Related Topic