package com.github.filosganga.geogson.gson; import com.github.filosganga.geogson.model.Feature; import com.github.filosganga.geogson.model.Geometry; import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import java.io.IOException; import java.util.HashMap; import java.util.Map; /** * The Gson TypeAdapter to serialize/de-serialize {@link Feature} instances. */ public class FeatureAdapter extends TypeAdapter<Feature> { public static final String FEATURE_TYPE = "Feature"; public static final String PROPERTIES_NAME = "properties"; public static final String GEOMETRY_NAME = "geometry"; public static final String ID_NAME = "id"; public static final String TYPE_NAME = "type"; private final Gson gson; public FeatureAdapter(Gson gson) { this.gson = gson; } @Override public void write(JsonWriter out, Feature value) throws IOException { if (value == null) { out.nullValue(); } else { out.beginObject(); if(value.id().isPresent()) { out.name(ID_NAME).value(value.id().get()); } out.name(TYPE_NAME).value(FEATURE_TYPE); writeProperties(out, value); writeGeometry(out, value); out.endObject(); } } private void writeGeometry(JsonWriter out, Feature value) throws IOException { out.name(GEOMETRY_NAME); gson.getAdapter(Geometry.class).write(out, value.geometry()); } private void writeProperties(JsonWriter out, Feature value) throws IOException { out.name(PROPERTIES_NAME); out.beginObject(); for(String key : value.properties().keySet()) { out.name(key); JsonElement propertyValue = gson.toJsonTree(value.properties().get(key)); gson.toJson(propertyValue, out); } out.endObject(); } @Override public Feature read(JsonReader in) throws IOException { Feature feature = null; if (in.peek() == JsonToken.NULL) { in.nextNull(); } else if (in.peek() == JsonToken.BEGIN_OBJECT) { in.beginObject(); Optional<String> id = Optional.absent(); Map<String, JsonElement> properties = null; Geometry<?> geometry = null; while (in.hasNext()) { String name = in.nextName(); if (TYPE_NAME.equals(name)) { String value = in.nextString(); if(!value.equalsIgnoreCase(FEATURE_TYPE)) { throw new IllegalArgumentException("The given json is not a valid Feature, the type must be Feature, current type=" + value); } } else if (PROPERTIES_NAME.equals(name)) { properties = readProperties(in); } else if (GEOMETRY_NAME.equals(name)) { geometry = gson.fromJson(in, Geometry.class); } else if (ID_NAME.equals(name)) { id = Optional.of(in.nextString()); } else { // Skip unknown value. in.skipValue(); } } if (properties == null) { throw new IllegalArgumentException("Required field 'properties' is missing"); } if (geometry == null) { throw new IllegalArgumentException("Required field 'geometry' is missing"); } feature = new Feature(geometry, ImmutableMap.copyOf(properties), id); in.endObject(); } else { throw new IllegalArgumentException("The given json is not a valid Feature: " + in.peek()); } return feature; } private Map<String, JsonElement> readProperties(JsonReader in) throws IOException { Map<String, JsonElement> result = new HashMap<>(); JsonParser parser = new JsonParser(); in.beginObject(); while (in.peek() != JsonToken.END_OBJECT) { String name = in.nextName(); JsonElement value = parser.parse(in); result.put(name, value); } in.endObject(); return result; } }