1
\$\begingroup\$

I am trying to write a parser from JSON data which I get from Google requesting coordinates of a city, which will create my specified object structure. For parsing, I've written a custom TypeAdapter.

It is my first time working with Gson, so probably my parsing method can be improved. Any suggestions?

JSON I receive:

    {
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "Los Angeles",
               "short_name" : "Los Angeles",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "Los Angeles County",
               "short_name" : "Los Angeles 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" ]
            }
         ],
         "formatted_address" : "Los Angeles, CA, USA",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 34.3373061,
                  "lng" : -118.1552891
               },
               "southwest" : {
                  "lat" : 33.7036917,
                  "lng" : -118.6681759
               }
            },
            "location" : {
               "lat" : 34.0522342,
               "lng" : -118.2436849
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 34.3373061,
                  "lng" : -118.1552891
               },
               "southwest" : {
                  "lat" : 33.7036917,
                  "lng" : -118.6681759
               }
            }
         },
         "partial_match" : true,
         "place_id" : "ChIJE9on3F3HwoAR9AhGJW_fL-I",
         "types" : [ "locality", "political" ]
      }
   ],
   "status" : "OK"
}

My POJO: only fields, without setters and getters to save space.

    public class GeoLocation {

    private String location_longName;
    private String location_shortName;
    private String country_longName;
    private String country_shortName;

    private String forrmatedAddress;

    private GeoCoordinates locationCordinates;
}

    public class GeoCoordinates {

    private Point northeastBounds;
    private Point southwestBounds;

    private Point northeastViewport;
    private Point southwestViewport;
    private Point location;
}

Custom TypeAdapter:

public class GeoLocationAdapter extends TypeAdapter<GeoLocation> {

    @Override
    public void write(JsonWriter jsonWriter, GeoLocation location) throws IOException {

    }

    @Override
    public GeoLocation read(JsonReader jsonReader) throws IOException {

        GeoLocation location = parsing(jsonReader);

        return location;
    }

    private GeoLocation parsing(JsonReader reader) throws IOException {
        GeoLocation location = new GeoLocation();
        GeoCoordinates coordinates = new GeoCoordinates();
        location.setLocationCordinates(coordinates);

        while (reader.peek() != JsonToken.END_DOCUMENT) {
            if (reader.peek() == JsonToken.NAME) {
                switch (reader.nextName()) {
                    case "results":
                    case "geometry":
                        break;
                    case "address_components":
                        reader.beginArray();
                        int i = 0;
                        String longName = null;
                        String shortName = null;
                        for (; ; ) {
                            if (reader.peek() == JsonToken.BEGIN_OBJECT) {
                                reader.beginObject();
                            }
                            if (reader.peek() == JsonToken.NAME) {
                                switch (reader.nextName()) {
                                    case "long_name":
                                        longName = reader.nextString();
                                        break;
                                    case "short_name":
                                        shortName = reader.nextString();
                                        break;
                                    case "types":
                                        while (reader.peek() != JsonToken.END_OBJECT) {
                                            reader.skipValue();
                                        }
                                        break;
                                }
                            }

                            if (reader.peek() == JsonToken.END_OBJECT) {
                                if (0 == i++) {
                                    location.setLocation_longName(longName);
                                    location.setLocation_shortName(shortName);
                                }
                                reader.endObject();
                            }

                            if (reader.peek() == JsonToken.END_ARRAY) {
                                location.setCountry_longName(longName);
                                location.setCountry_shortName(shortName);
                                reader.endArray();
                                break;
                            }
                        }
                        break;
                    case "formatted_address":
                        location.setForrmatedAddress(reader.nextString());
                        break;
                    case "bounds":
                        reader.beginObject();
                        for (; ; ) {
                            if (reader.peek() == JsonToken.NAME) {
                                switch (reader.nextName()) {
                                    case "northeast":
                                        reader.beginObject();
                                        location.getLocationCordinates().setNortheastBounds(parseCoordinates(reader));
                                        reader.endObject();
                                        break;
                                    case "southwest":
                                        reader.beginObject();
                                        location.getLocationCordinates().setSouthwestBounds(parseCoordinates(reader));
                                        reader.endObject();
                                        break;
                                }
                                if (reader.peek() == JsonToken.END_OBJECT) {
                                    reader.endObject();
                                    break;
                                }
                            }
                        }
                        break;
                    case "location":
                        reader.beginObject();
                        location.getLocationCordinates().setLocation(parseCoordinates(reader));
                        reader.endObject();
                        break;
                    case "viewport":
                        reader.beginObject();
                        for (; ; ) {
                            if (reader.peek() == JsonToken.NAME) {
                                switch (reader.nextName()) {
                                    case "northeast":
                                        reader.beginObject();
                                        location.getLocationCordinates().setNortheastViewport(parseCoordinates(reader));
                                        reader.endObject();
                                        break;
                                    case "southwest":
                                        reader.beginObject();
                                        location.getLocationCordinates().setSouthwestViewport(parseCoordinates(reader));
                                        reader.endObject();
                                        break;
                                }
                                if (reader.peek() == JsonToken.END_OBJECT) {
                                    reader.endObject();
                                    break;
                                }
                            }
                        }
                        break;
                    default:
                        reader.skipValue();
                        break;
                }
            }

            if (reader.peek() == JsonToken.BEGIN_OBJECT) {
                reader.beginObject();
            }

            if (reader.peek() == JsonToken.BEGIN_ARRAY) {
                reader.beginArray();
            }

            if (reader.peek() == JsonToken.END_OBJECT) {
                reader.endObject();
            }

            if (reader.peek() == JsonToken.END_ARRAY) {
                reader.endArray();
            }
        }
        return location;
    }

    private Point parseCoordinates(JsonReader reader) throws IOException {
        Double lat = null;
        Double lng = null;
        while (reader.peek() != JsonToken.END_OBJECT) {
            switch (reader.nextName()) {
                case "lat":
                    lat = reader.nextDouble();
                    break;
                case "lng":
                    lng = reader.nextDouble();
                    break;
            }
        }

        return new Point(lat, lng);
    }
}

Calling:

            GsonBuilder builder = new GsonBuilder();
        builder.registerTypeAdapter(GeoLocation.class, new GeoLocationAdapter());
        Gson gson = builder.create();

        GeoLocation locationObj = gson.fromJson(full, GeoLocation.class);

Please provide any improvements that can be made to code for ac-heaving better readability and performance. Also, can I leave the write method empty if I'm not planning to convert the result object back to JSON?

\$\endgroup\$
  • \$\begingroup\$ Any reason not to use a JsonParser? The code would be much shorter. \$\endgroup\$ – Tunaki Jan 24 '16 at 21:56
  • \$\begingroup\$ was not aware of it, should try probably. Maybe you can explain a little how to implement it in my case? \$\endgroup\$ – Edgar Jan 25 '16 at 8:01
1
\$\begingroup\$

You can parse the complete response easily using Google's Gson library:

class GeoResponse {
    List<Result> results;
    String status;

    static class Result {
        List<AddressComponent> address_components;
        String formatted_address;
        Geometry geometry;
        boolean partial_match;
        String place_id;
        List<String> types;

        static class AddressComponent {
            String long_name, short_name;
            List<String> types;
        }

        static class Geometry {
            Rect bounds;
            LatLng location;
            String location_type;
            Rect viewport;

            static class Rect {
                LatLng northeast, southwest;
            }

            static class LatLng {
                double lat, lng;
            }
        }
    }
}

...
import com.google.gson.Gson;

class GeoResponseParser {
    Gson gson = new Gson();
    GeoResponse parse(String responseStr) {
        return gson.fromJson(responseStr, GeoResponse.class);
    }
}
\$\endgroup\$
  • \$\begingroup\$ yea it works, but I wanted to make different structure of object. \$\endgroup\$ – Edgar Jan 30 '16 at 9:01
  • \$\begingroup\$ @Edgar Then I would recommend letting Gson do the conversion to a Java object and then convert that object to one of the structure you want. \$\endgroup\$ – Solomonoff's Secret Jan 30 '16 at 14:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.