From e155bc584fb904539291dec8479622922119c27d Mon Sep 17 00:00:00 2001 From: osana Date: Thu, 13 Dec 2018 15:41:25 -0500 Subject: [PATCH 1/2] removed AutoValue from geoJson --- .../java/com/mapbox/geojson/BoundingBox.java | 71 ++++- .../main/java/com/mapbox/geojson/Feature.java | 262 ++++++++++++++++-- .../com/mapbox/geojson/FeatureCollection.java | 210 ++++++++++++-- .../mapbox/geojson/GeometryCollection.java | 219 ++++++++++++++- .../java/com/mapbox/geojson/LineString.java | 184 +++++++++++- .../com/mapbox/geojson/MultiLineString.java | 192 ++++++++++++- .../java/com/mapbox/geojson/MultiPoint.java | 182 +++++++++++- .../java/com/mapbox/geojson/MultiPolygon.java | 192 ++++++++++++- .../main/java/com/mapbox/geojson/Point.java | 192 ++++++++++++- .../main/java/com/mapbox/geojson/Polygon.java | 199 +++++++++++-- .../geojson/gson/CoordinateTypeAdapter.java | 13 + .../geojson/gson/GeoJsonAdapterFactory.java | 47 +++- .../geojson/gson/GeometryDeserializer.java | 2 +- .../mapbox/geojson/gson/GeometryGeoJson.java | 24 +- .../geojson/gson/GeometryTypeAdapter.java | 11 +- .../geojson/gson/PointDeserializer.java | 35 ++- .../java/com/mapbox/geojson/FeatureTest.java | 55 +++- .../geojson/GeometryCollectionTest.java | 21 +- .../java/com/mapbox/geojson/GeometryTest.java | 65 ++++- .../com/mapbox/geojson/LineStringTest.java | 23 +- .../java/com/mapbox/geojson/PointTest.java | 36 ++- .../geojson/gson/PointDeserializerTest.java | 2 +- 22 files changed, 2062 insertions(+), 175 deletions(-) diff --git a/services-geojson/src/main/java/com/mapbox/geojson/BoundingBox.java b/services-geojson/src/main/java/com/mapbox/geojson/BoundingBox.java index 9dd5c5246..339debb73 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/BoundingBox.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/BoundingBox.java @@ -5,11 +5,12 @@ import android.support.annotation.FloatRange; import android.support.annotation.NonNull; -import com.google.auto.value.AutoValue; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; import com.mapbox.geojson.constants.GeoJsonConstants; +import com.mapbox.geojson.gson.BoundingBoxDeserializer; +import com.mapbox.geojson.gson.BoundingBoxSerializer; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; import java.io.Serializable; @@ -29,8 +30,11 @@ * * @since 3.0.0 */ -@AutoValue -public abstract class BoundingBox implements Serializable { +public class BoundingBox implements Serializable { + + private final Point southwest; + + private final Point northeast; /** * Create a new instance of this class by passing in a formatted valid JSON String. @@ -43,6 +47,7 @@ public abstract class BoundingBox implements Serializable { public static BoundingBox fromJson(String json) { Gson gson = new GsonBuilder() .registerTypeAdapterFactory(GeoJsonAdapterFactory.create()) + .registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()) .create(); return gson.fromJson(json, BoundingBox.class); } @@ -59,7 +64,7 @@ public static BoundingBox fromJson(String json) { * @since 3.0.0 */ public static BoundingBox fromPoints(@NonNull Point southwest, @NonNull Point northeast) { - return new AutoValue_BoundingBox(southwest, northeast); + return new BoundingBox(southwest, northeast); } /** @@ -130,7 +135,7 @@ public static BoundingBox fromLngLats( @FloatRange(from = MIN_LATITUDE, to = GeoJsonConstants.MAX_LATITUDE) double south, @FloatRange(from = MIN_LONGITUDE, to = GeoJsonConstants.MAX_LONGITUDE) double east, @FloatRange(from = MIN_LATITUDE, to = GeoJsonConstants.MAX_LATITUDE) double north) { - return new AutoValue_BoundingBox(Point.fromLngLat(west, south), Point.fromLngLat(east, north)); + return new BoundingBox(Point.fromLngLat(west, south), Point.fromLngLat(east, north)); } /** @@ -156,11 +161,21 @@ public static BoundingBox fromLngLats( @FloatRange(from = MIN_LONGITUDE, to = GeoJsonConstants.MAX_LONGITUDE) double east, @FloatRange(from = MIN_LATITUDE, to = GeoJsonConstants.MAX_LATITUDE) double north, double northEastAltitude) { - return new AutoValue_BoundingBox( + return new BoundingBox( Point.fromLngLat(west, south, southwestAltitude), Point.fromLngLat(east, north, northEastAltitude)); } + BoundingBox(Point southwest, Point northeast) { + if (southwest == null) { + throw new NullPointerException("Null southwest"); + } + this.southwest = southwest; + if (northeast == null) { + throw new NullPointerException("Null northeast"); + } + this.northeast = northeast; + } /** * Provides the {@link Point} which represents the southwest corner of this bounding box when the * map is facing due north. @@ -169,7 +184,9 @@ public static BoundingBox fromLngLats( * @since 3.0.0 */ @NonNull - public abstract Point southwest(); + public Point southwest() { + return southwest; + } /** * Provides the {@link Point} which represents the northeast corner of this bounding box when the @@ -179,7 +196,9 @@ public static BoundingBox fromLngLats( * @since 3.0.0 */ @NonNull - public abstract Point northeast(); + public Point northeast() { + return northeast; + } /** * Convenience method for getting the bounding box most westerly point (longitude) as a double @@ -233,7 +252,7 @@ public final double north() { * @since 3.0.0 */ public static TypeAdapter typeAdapter(Gson gson) { - return new AutoValue_BoundingBox.GsonTypeAdapter(gson); + return null; //new BoundingBox.GsonTypeAdapter(gson); } /** @@ -245,9 +264,39 @@ public static TypeAdapter typeAdapter(Gson gson) { */ public final String toJson() { Gson gson = new GsonBuilder() - .setPrettyPrinting() - .registerTypeAdapterFactory(GeoJsonAdapterFactory.create()) + .registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()) .create(); return gson.toJson(this, BoundingBox.class); } + + @Override + public String toString() { + return "BoundingBox{" + + "southwest=" + southwest + ", " + + "northeast=" + northeast + + "}"; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof BoundingBox) { + BoundingBox that = (BoundingBox) o; + return (this.southwest.equals(that.southwest())) + && (this.northeast.equals(that.northeast())); + } + return false; + } + + @Override + public int hashCode() { + int h$ = 1; + h$ *= 1000003; + h$ ^= southwest.hashCode(); + h$ *= 1000003; + h$ ^= northeast.hashCode(); + return h$; + } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/Feature.java b/services-geojson/src/main/java/com/mapbox/geojson/Feature.java index fa49527ef..4a131102c 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/Feature.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/Feature.java @@ -2,19 +2,25 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.google.auto.value.AutoValue; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.google.gson.typeadapters.RuntimeTypeAdapterFactory; import com.mapbox.geojson.gson.BoundingBoxDeserializer; import com.mapbox.geojson.gson.BoundingBoxSerializer; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; import com.mapbox.geojson.gson.GeometryDeserializer; +import com.mapbox.geojson.gson.GeometryTypeAdapter; import com.mapbox.geojson.gson.PointDeserializer; import com.mapbox.geojson.gson.PointSerializer; +import java.io.IOException; + /** * This defines a GeoJson Feature object which represents a spatially bound thing. Every Feature * object is a GeoJson object no matter where it occurs in a GeoJson text. A Feature object will @@ -45,11 +51,20 @@ * * @since 1.0.0 */ -@AutoValue -public abstract class Feature implements GeoJson { +public final class Feature implements GeoJson { private static final String TYPE = "Feature"; + private final String type; + + private final BoundingBox bbox; + + private final String id; + + private final Geometry geometry; + + private final JsonObject properties; + /** * Create a new instance of this class by passing in a formatted valid JSON String. If you are * creating a Feature object from scratch it is better to use one of the other provided static @@ -61,11 +76,15 @@ public abstract class Feature implements GeoJson { * @since 1.0.0 */ public static Feature fromJson(@NonNull String json) { + GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); + gson.registerTypeAdapter(Point.class, new PointDeserializer()); gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); + + gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); gson.registerTypeAdapter(Geometry.class, new GeometryDeserializer()); + Feature feature = gson.create().fromJson(json, Feature.class); // Even thought properties are Nullable, @@ -74,7 +93,7 @@ public static Feature fromJson(@NonNull String json) { if (feature.properties() != null) { return feature; } - return new AutoValue_Feature(TYPE, feature.bbox(), + return new Feature(TYPE, feature.bbox(), feature.id(), feature.geometry(), new JsonObject()); } @@ -87,7 +106,7 @@ public static Feature fromJson(@NonNull String json) { * @since 1.0.0 */ public static Feature fromGeometry(@Nullable Geometry geometry) { - return new AutoValue_Feature(TYPE, null, null, geometry, new JsonObject()); + return new Feature(TYPE, null, null, geometry, new JsonObject()); } /** @@ -101,7 +120,7 @@ public static Feature fromGeometry(@Nullable Geometry geometry) { * @since 1.0.0 */ public static Feature fromGeometry(@Nullable Geometry geometry, @Nullable BoundingBox bbox) { - return new AutoValue_Feature(TYPE, bbox, null, geometry, new JsonObject()); + return new Feature(TYPE, bbox, null, geometry, new JsonObject()); } /** @@ -115,7 +134,7 @@ public static Feature fromGeometry(@Nullable Geometry geometry, @Nullable Boundi * @since 1.0.0 */ public static Feature fromGeometry(@Nullable Geometry geometry, @Nullable JsonObject properties) { - return new AutoValue_Feature(TYPE, null, null, geometry, + return new Feature(TYPE, null, null, geometry, properties == null ? new JsonObject() : properties); } @@ -132,7 +151,7 @@ public static Feature fromGeometry(@Nullable Geometry geometry, @Nullable JsonOb */ public static Feature fromGeometry(@Nullable Geometry geometry, @Nullable JsonObject properties, @Nullable BoundingBox bbox) { - return new AutoValue_Feature(TYPE, bbox, null, geometry, + return new Feature(TYPE, bbox, null, geometry, properties == null ? new JsonObject() : properties); } @@ -148,7 +167,7 @@ public static Feature fromGeometry(@Nullable Geometry geometry, @Nullable JsonOb */ public static Feature fromGeometry(@Nullable Geometry geometry, @Nullable JsonObject properties, @Nullable String id) { - return new AutoValue_Feature(TYPE, null, id, geometry, + return new Feature(TYPE, null, id, geometry, properties == null ? new JsonObject() : properties); } @@ -165,10 +184,22 @@ public static Feature fromGeometry(@Nullable Geometry geometry, @Nullable JsonOb */ public static Feature fromGeometry(@Nullable Geometry geometry, @NonNull JsonObject properties, @Nullable String id, @Nullable BoundingBox bbox) { - return new AutoValue_Feature(TYPE, bbox, id, geometry, + return new Feature(TYPE, bbox, id, geometry, properties == null ? new JsonObject() : properties); } + Feature(String type, @Nullable BoundingBox bbox, @Nullable String id, + @Nullable Geometry geometry, @Nullable JsonObject properties) { + if (type == null) { + throw new NullPointerException("Null type"); + } + this.type = type; + this.bbox = bbox; + this.id = id; + this.geometry = geometry; + this.properties = properties; + } + /** * This describes the TYPE of GeoJson geometry this object is, thus this will always return * {@link Feature}. @@ -179,7 +210,9 @@ public static Feature fromGeometry(@Nullable Geometry geometry, @NonNull JsonObj */ @NonNull @Override - public abstract String type(); + public String type() { + return type; + } /** * A Feature Collection might have a member named {@code bbox} to include information on the @@ -193,7 +226,9 @@ public static Feature fromGeometry(@Nullable Geometry geometry, @NonNull JsonObj */ @Nullable @Override - public abstract BoundingBox bbox(); + public BoundingBox bbox() { + return bbox; + } /** * A feature may have a commonly used identifier which is either a unique String or number. @@ -203,7 +238,9 @@ public static Feature fromGeometry(@Nullable Geometry geometry, @NonNull JsonObj * @since 1.0.0 */ @Nullable - public abstract String id(); + public String id() { + return id; + } /** * The geometry which makes up this feature. A Geometry object represents points, curves, and @@ -214,7 +251,9 @@ public static Feature fromGeometry(@Nullable Geometry geometry, @NonNull JsonObj * @since 1.0.0 */ @Nullable - public abstract Geometry geometry(); + public Geometry geometry() { + return geometry; + } /** * This contains the JSON object which holds the feature properties. The value of the properties @@ -224,7 +263,9 @@ public static Feature fromGeometry(@Nullable Geometry geometry, @NonNull JsonObj * @since 1.0.0 */ @Nullable - public abstract JsonObject properties(); + public JsonObject properties() { + return properties; + } /** * This takes the currently defined values found inside this instance and converts it to a GeoJson @@ -235,14 +276,15 @@ public static Feature fromGeometry(@Nullable Geometry geometry, @NonNull JsonObj */ @Override public String toJson() { + GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapter(Point.class, new PointSerializer()); + gson.registerTypeAdapter(Geometry.class, new GeometryTypeAdapter()); gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()); // Empty properties -> should not appear in json string Feature feature = this; if (properties().size() == 0) { - feature = new AutoValue_Feature(TYPE, bbox(), id(), geometry(), null); + feature = new Feature(TYPE, bbox(), id(), geometry(), null); } return gson.create().toJson(feature); @@ -256,7 +298,7 @@ public String toJson() { * @since 3.0.0 */ public static TypeAdapter typeAdapter(Gson gson) { - return new AutoValue_Feature.GsonTypeAdapter(gson); + return new Feature.GsonTypeAdapter(gson); } /** @@ -401,4 +443,186 @@ public boolean hasProperty(String key) { public boolean hasNonNullValueForProperty(String key) { return hasProperty(key) && !getProperty(key).isJsonNull(); } + + @Override + public String toString() { + return "Feature{" + + "type=" + type + ", " + + "bbox=" + bbox + ", " + + "id=" + id + ", " + + "geometry=" + geometry + ", " + + "properties=" + properties + + "}"; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof Feature) { + Feature that = (Feature) o; + return (this.type.equals(that.type())) + && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) + && ((this.id == null) ? (that.id() == null) : this.id.equals(that.id())) + && ((this.geometry == null) ? (that.geometry() == null) : this.geometry.equals(that.geometry())) + && ((this.properties == null) ? (that.properties() == null) : this.properties.equals(that.properties())); + } + return false; + } + + @Override + public int hashCode() { + int h$ = 1; + h$ *= 1000003; + h$ ^= type.hashCode(); + h$ *= 1000003; + h$ ^= (bbox == null) ? 0 : bbox.hashCode(); + h$ *= 1000003; + h$ ^= (id == null) ? 0 : id.hashCode(); + h$ *= 1000003; + h$ ^= (geometry == null) ? 0 : geometry.hashCode(); + h$ *= 1000003; + h$ ^= (properties == null) ? 0 : properties.hashCode(); + return h$; + } + + public static final class GsonTypeAdapter extends TypeAdapter { + private volatile TypeAdapter string_adapter; + private volatile TypeAdapter boundingBox_adapter; + private volatile TypeAdapter geometry_adapter; + private volatile TypeAdapter jsonObject_adapter; + private final Gson gson; + public GsonTypeAdapter(Gson gson) { + this.gson = gson; + } + @Override + @SuppressWarnings("unchecked") + public void write(JsonWriter jsonWriter, Feature object) throws IOException { + if (object == null) { + jsonWriter.nullValue(); + return; + } + jsonWriter.beginObject(); + jsonWriter.name("type"); + if (object.type() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + string_adapter.write(jsonWriter, object.type()); + } + jsonWriter.name("bbox"); + if (object.bbox() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + boundingBox_adapter.write(jsonWriter, object.bbox()); + } + jsonWriter.name("id"); + if (object.id() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + string_adapter.write(jsonWriter, object.id()); + } + jsonWriter.name("geometry"); + if (object.geometry() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter geometry_adapter = this.geometry_adapter; + if (geometry_adapter == null) { + this.geometry_adapter = geometry_adapter = gson.getAdapter(Geometry.class); + } + geometry_adapter.write(jsonWriter, object.geometry()); + } + jsonWriter.name("properties"); + if (object.properties() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter jsonObject_adapter = this.jsonObject_adapter; + if (jsonObject_adapter == null) { + this.jsonObject_adapter = jsonObject_adapter = gson.getAdapter(JsonObject.class); + } + jsonObject_adapter.write(jsonWriter, object.properties()); + } + jsonWriter.endObject(); + } + @Override + @SuppressWarnings("unchecked") + public Feature read(JsonReader jsonReader) throws IOException { + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + return null; + } + jsonReader.beginObject(); + String type = null; + BoundingBox bbox = null; + String id = null; + Geometry geometry = null; + JsonObject properties = null; + while (jsonReader.hasNext()) { + String _name = jsonReader.nextName(); + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + continue; + } + switch (_name) { + case "type": { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + type = string_adapter.read(jsonReader); + break; + } + case "bbox": { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + bbox = boundingBox_adapter.read(jsonReader); + break; + } + case "id": { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + id = string_adapter.read(jsonReader); + break; + } + case "geometry": { + TypeAdapter geometry_adapter = this.geometry_adapter; + if (geometry_adapter == null) { + this.geometry_adapter = geometry_adapter = gson.getAdapter(Geometry.class); + } + geometry = geometry_adapter.read(jsonReader); + break; + } + case "properties": { + TypeAdapter jsonObject_adapter = this.jsonObject_adapter; + if (jsonObject_adapter == null) { + this.jsonObject_adapter = jsonObject_adapter = gson.getAdapter(JsonObject.class); + } + properties = jsonObject_adapter.read(jsonReader); + break; + } + default: { + jsonReader.skipValue(); + } + } + } + jsonReader.endObject(); + return new Feature(type, bbox, id, geometry, properties); + } + } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/FeatureCollection.java b/services-geojson/src/main/java/com/mapbox/geojson/FeatureCollection.java index 341dfacd8..5fea09704 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/FeatureCollection.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/FeatureCollection.java @@ -2,17 +2,23 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.google.auto.value.AutoValue; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.google.gson.typeadapters.RuntimeTypeAdapterFactory; import com.mapbox.geojson.gson.BoundingBoxDeserializer; import com.mapbox.geojson.gson.BoundingBoxSerializer; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; import com.mapbox.geojson.gson.GeometryDeserializer; +import com.mapbox.geojson.gson.GeometryTypeAdapter; import com.mapbox.geojson.gson.PointDeserializer; import com.mapbox.geojson.gson.PointSerializer; +import java.io.IOException; import java.util.Arrays; import java.util.List; @@ -36,11 +42,16 @@ * * @since 1.0.0 */ -@AutoValue -public abstract class FeatureCollection implements GeoJson { +public final class FeatureCollection implements GeoJson { private static final String TYPE = "FeatureCollection"; + private final String type; + + private final BoundingBox bbox; + + private final List features; + /** * Create a new instance of this class by passing in a formatted valid JSON String. If you are * creating a FeatureCollection object from scratch it is better to use one of the other provided @@ -52,11 +63,25 @@ public abstract class FeatureCollection implements GeoJson { * @since 1.0.0 */ public static FeatureCollection fromJson(@NonNull String json) { +// final RuntimeTypeAdapterFactory geometryFactory = RuntimeTypeAdapterFactory +// .of(Geometry.class, "type") +// .registerSubtype(GeometryCollection.class, "GeometryCollection") +// .registerSubtype(Point.class, "Point") +// .registerSubtype(MultiPoint.class, "MultiPoint") +// .registerSubtype(LineString.class, "LineString") +// .registerSubtype(MultiLineString.class, "MultiLineString") +// .registerSubtype(Polygon.class, "Polygon") +// .registerSubtype(MultiPolygon.class, "MultiPolygon"); + GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); + //gson.registerTypeAdapterFactory(geometryFactory); + gson.registerTypeAdapter(Point.class, new PointDeserializer()); - gson.registerTypeAdapter(Geometry.class, new GeometryDeserializer()); gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); + + gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); + gson.registerTypeAdapter(Geometry.class, new GeometryDeserializer()); + return gson.create().fromJson(json, FeatureCollection.class); } @@ -71,7 +96,7 @@ public static FeatureCollection fromJson(@NonNull String json) { * @since 1.0.0 */ public static FeatureCollection fromFeatures(@NonNull Feature[] features) { - return new AutoValue_FeatureCollection(TYPE, null, Arrays.asList(features)); + return new FeatureCollection(TYPE, null, Arrays.asList(features)); } /** @@ -84,7 +109,7 @@ public static FeatureCollection fromFeatures(@NonNull Feature[] features) { * @since 1.0.0 */ public static FeatureCollection fromFeatures(@NonNull List features) { - return new AutoValue_FeatureCollection(TYPE, null, features); + return new FeatureCollection(TYPE, null, features); } /** @@ -100,7 +125,7 @@ public static FeatureCollection fromFeatures(@NonNull List features) { */ public static FeatureCollection fromFeatures(@NonNull Feature[] features, @Nullable BoundingBox bbox) { - return new AutoValue_FeatureCollection(TYPE, bbox, Arrays.asList(features)); + return new FeatureCollection(TYPE, bbox, Arrays.asList(features)); } /** @@ -116,7 +141,7 @@ public static FeatureCollection fromFeatures(@NonNull Feature[] features, */ public static FeatureCollection fromFeatures(@NonNull List features, @Nullable BoundingBox bbox) { - return new AutoValue_FeatureCollection(TYPE, bbox, features); + return new FeatureCollection(TYPE, bbox, features); } /** @@ -129,7 +154,7 @@ public static FeatureCollection fromFeatures(@NonNull List features, */ public static FeatureCollection fromFeature(@NonNull Feature feature) { List featureList = Arrays.asList(feature); - return new AutoValue_FeatureCollection(TYPE, null, featureList); + return new FeatureCollection(TYPE, null, featureList); } /** @@ -144,7 +169,16 @@ public static FeatureCollection fromFeature(@NonNull Feature feature) { public static FeatureCollection fromFeature(@NonNull Feature feature, @Nullable BoundingBox bbox) { List featureList = Arrays.asList(feature); - return new AutoValue_FeatureCollection(TYPE, bbox, featureList); + return new FeatureCollection(TYPE, bbox, featureList); + } + + FeatureCollection(String type, @Nullable BoundingBox bbox, @Nullable List features) { + if (type == null) { + throw new NullPointerException("Null type"); + } + this.type = type; + this.bbox = bbox; + this.features = features; } /** @@ -157,7 +191,9 @@ public static FeatureCollection fromFeature(@NonNull Feature feature, */ @NonNull @Override - public abstract String type(); + public String type() { + return type; + } /** * A Feature Collection might have a member named {@code bbox} to include information on the @@ -171,7 +207,9 @@ public static FeatureCollection fromFeature(@NonNull Feature feature, */ @Nullable @Override - public abstract BoundingBox bbox(); + public BoundingBox bbox() { + return bbox; + } /** * This provides the list of feature making up this Feature Collection. Note that if the @@ -182,7 +220,9 @@ public static FeatureCollection fromFeature(@NonNull Feature feature, * @since 1.0.0 */ @Nullable - public abstract List features(); + public List features() { + return features; + } /** * This takes the currently defined values found inside this instance and converts it to a GeoJson @@ -193,9 +233,12 @@ public static FeatureCollection fromFeature(@NonNull Feature feature, */ @Override public String toJson() { + GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapter(Point.class, new PointSerializer()); + + gson.registerTypeAdapter(Geometry.class, new GeometryTypeAdapter()); gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()); + return gson.create().toJson(this); } @@ -207,6 +250,141 @@ public String toJson() { * @since 3.0.0 */ public static TypeAdapter typeAdapter(Gson gson) { - return new AutoValue_FeatureCollection.GsonTypeAdapter(gson); + return new FeatureCollection.GsonTypeAdapter(gson); + } + + @Override + public String toString() { + return "FeatureCollection{" + + "type=" + type + ", " + + "bbox=" + bbox + ", " + + "features=" + features + + "}"; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof FeatureCollection) { + FeatureCollection that = (FeatureCollection) o; + return (this.type.equals(that.type())) + && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) + && ((this.features == null) ? (that.features() == null) : this.features.equals(that.features())); + } + return false; + } + + @Override + public int hashCode() { + int h$ = 1; + h$ *= 1000003; + h$ ^= type.hashCode(); + h$ *= 1000003; + h$ ^= (bbox == null) ? 0 : bbox.hashCode(); + h$ *= 1000003; + h$ ^= (features == null) ? 0 : features.hashCode(); + return h$; + } + + public static final class GsonTypeAdapter extends TypeAdapter { + private volatile TypeAdapter string_adapter; + private volatile TypeAdapter boundingBox_adapter; + private volatile TypeAdapter> list__feature_adapter; + private final Gson gson; + public GsonTypeAdapter(Gson gson) { + this.gson = gson; + } + @Override + @SuppressWarnings("unchecked") + public void write(JsonWriter jsonWriter, FeatureCollection object) throws IOException { + if (object == null) { + jsonWriter.nullValue(); + return; + } + jsonWriter.beginObject(); + jsonWriter.name("type"); + if (object.type() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + string_adapter.write(jsonWriter, object.type()); + } + jsonWriter.name("bbox"); + if (object.bbox() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + boundingBox_adapter.write(jsonWriter, object.bbox()); + } + jsonWriter.name("features"); + if (object.features() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter> list__feature_adapter = this.list__feature_adapter; + if (list__feature_adapter == null) { + this.list__feature_adapter = list__feature_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Feature.class)); + } + list__feature_adapter.write(jsonWriter, object.features()); + } + jsonWriter.endObject(); + } + @Override + @SuppressWarnings("unchecked") + public FeatureCollection read(JsonReader jsonReader) throws IOException { + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + return null; + } + jsonReader.beginObject(); + String type = null; + BoundingBox bbox = null; + List features = null; + while (jsonReader.hasNext()) { + String _name = jsonReader.nextName(); + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + continue; + } + switch (_name) { + case "type": { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + type = string_adapter.read(jsonReader); + break; + } + case "bbox": { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + bbox = boundingBox_adapter.read(jsonReader); + break; + } + case "features": { + TypeAdapter> list__feature_adapter = this.list__feature_adapter; + if (list__feature_adapter == null) { + this.list__feature_adapter = list__feature_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Feature.class)); + } + features = list__feature_adapter.read(jsonReader); + break; + } + default: { + jsonReader.skipValue(); + } + } + } + jsonReader.endObject(); + return new FeatureCollection(type, bbox, features); + } } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/GeometryCollection.java b/services-geojson/src/main/java/com/mapbox/geojson/GeometryCollection.java index 63cf7cc1d..ac988df49 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/GeometryCollection.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/GeometryCollection.java @@ -3,17 +3,23 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.google.auto.value.AutoValue; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.google.gson.typeadapters.RuntimeTypeAdapterFactory; import com.mapbox.geojson.gson.BoundingBoxDeserializer; import com.mapbox.geojson.gson.BoundingBoxSerializer; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; import com.mapbox.geojson.gson.GeometryDeserializer; +import com.mapbox.geojson.gson.GeometryTypeAdapter; import com.mapbox.geojson.gson.PointDeserializer; import com.mapbox.geojson.gson.PointSerializer; +import java.io.IOException; import java.io.Serializable; import java.util.Arrays; import java.util.List; @@ -60,11 +66,16 @@ * * @since 1.0.0 */ -@AutoValue -public abstract class GeometryCollection implements Geometry, Serializable { +public final class GeometryCollection implements Geometry, Serializable { private static final String TYPE = "GeometryCollection"; + private final String type; + + private final BoundingBox bbox; + + private final List geometries; + /** * Create a new instance of this class by passing in a formatted valid JSON String. If you are * creating a GeometryCollection object from scratch it is better to use one of the other provided @@ -76,11 +87,26 @@ public abstract class GeometryCollection implements Geometry, Serializable { * @since 1.0.0 */ public static GeometryCollection fromJson(String json) { + +// final RuntimeTypeAdapterFactory geometryFactory = RuntimeTypeAdapterFactory +// .of(Geometry.class, "type") +// .registerSubtype(GeometryCollection.class, "GeometryCollection") +// .registerSubtype(Point.class, "Point") +// .registerSubtype(MultiPoint.class, "MultiPoint") +// .registerSubtype(LineString.class, "LineString") +// .registerSubtype(MultiLineString.class, "MultiLineString") +// .registerSubtype(Polygon.class, "Polygon") +// .registerSubtype(MultiPolygon.class, "MultiPolygon"); + GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); +// gson.registerTypeAdapterFactory(geometryFactory); + gson.registerTypeAdapter(Point.class, new PointDeserializer()); gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); + + gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); gson.registerTypeAdapter(Geometry.class, new GeometryDeserializer()); + return gson.create().fromJson(json, GeometryCollection.class); } @@ -93,7 +119,7 @@ public static GeometryCollection fromJson(String json) { * @since 1.0.0 */ public static GeometryCollection fromGeometries(@NonNull List geometries) { - return new AutoValue_GeometryCollection(TYPE, null, geometries); + return new GeometryCollection(TYPE, null, geometries); } /** @@ -107,7 +133,7 @@ public static GeometryCollection fromGeometries(@NonNull List geometri */ public static GeometryCollection fromGeometries(@NonNull List geometries, @Nullable BoundingBox bbox) { - return new AutoValue_GeometryCollection(TYPE, bbox, geometries); + return new GeometryCollection(TYPE, bbox, geometries); } /** @@ -120,7 +146,7 @@ public static GeometryCollection fromGeometries(@NonNull List geometri */ public static GeometryCollection fromGeometry(@NonNull Geometry geometry) { List geometries = Arrays.asList(geometry); - return new AutoValue_GeometryCollection(TYPE, null, geometries); + return new GeometryCollection(TYPE, null, geometries); } /** @@ -135,7 +161,19 @@ public static GeometryCollection fromGeometry(@NonNull Geometry geometry) { public static GeometryCollection fromGeometry(@NonNull Geometry geometry, @Nullable BoundingBox bbox) { List geometries = Arrays.asList(geometry); - return new AutoValue_GeometryCollection(TYPE, bbox, geometries); + return new GeometryCollection(TYPE, bbox, geometries); + } + + GeometryCollection(String type, @Nullable BoundingBox bbox, List geometries) { + if (type == null) { + throw new NullPointerException("Null type"); + } + this.type = type; + this.bbox = bbox; + if (geometries == null) { + throw new NullPointerException("Null geometries"); + } + this.geometries = geometries; } /** @@ -148,7 +186,9 @@ public static GeometryCollection fromGeometry(@NonNull Geometry geometry, */ @NonNull @Override - public abstract String type(); + public String type() { + return type; + } /** * A Feature Collection might have a member named {@code bbox} to include information on the @@ -162,7 +202,9 @@ public static GeometryCollection fromGeometry(@NonNull Geometry geometry, */ @Nullable @Override - public abstract BoundingBox bbox(); + public BoundingBox bbox() { + return bbox; + } /** * This provides the list of geometry making up this Geometry Collection. Note that if the @@ -173,7 +215,9 @@ public static GeometryCollection fromGeometry(@NonNull Geometry geometry, * @since 1.0.0 */ @NonNull - public abstract List geometries(); + public List geometries() { + return geometries; + } /** * This takes the currently defined values found inside this instance and converts it to a GeoJson @@ -184,8 +228,22 @@ public static GeometryCollection fromGeometry(@NonNull Geometry geometry, */ @Override public String toJson() { + +// final RuntimeTypeAdapterFactory geometryFactory = RuntimeTypeAdapterFactory +// .of(Geometry.class, "type") +// .registerSubtype(GeometryCollection.class, "GeometryCollection") +// .registerSubtype(Point.class, "Point") +// .registerSubtype(MultiPoint.class, "MultiPoint") +// .registerSubtype(LineString.class, "LineString") +// .registerSubtype(MultiLineString.class, "MultiLineString") +// .registerSubtype(Polygon.class, "Polygon") +// .registerSubtype(MultiPolygon.class, "MultiPolygon"); + GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapter(Point.class, new PointSerializer()); + // gson.registerTypeAdapterFactory(geometryFactory); + + gson.registerTypeAdapter(Geometry.class, new GeometryTypeAdapter()); + // gson.registerTypeAdapter(Point.class, new PointSerializer()); gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()); return gson.create().toJson(this); } @@ -198,6 +256,141 @@ public String toJson() { * @since 3.0.0 */ public static TypeAdapter typeAdapter(Gson gson) { - return new AutoValue_GeometryCollection.GsonTypeAdapter(gson); + return new GeometryCollection.GsonTypeAdapter(gson); + } + + @Override + public String toString() { + return "GeometryCollection{" + + "type=" + type + ", " + + "bbox=" + bbox + ", " + + "geometries=" + geometries + + "}"; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof GeometryCollection) { + GeometryCollection that = (GeometryCollection) o; + return (this.type.equals(that.type())) + && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) + && (this.geometries.equals(that.geometries())); + } + return false; + } + + @Override + public int hashCode() { + int h$ = 1; + h$ *= 1000003; + h$ ^= type.hashCode(); + h$ *= 1000003; + h$ ^= (bbox == null) ? 0 : bbox.hashCode(); + h$ *= 1000003; + h$ ^= geometries.hashCode(); + return h$; + } + + public static final class GsonTypeAdapter extends TypeAdapter { + private volatile TypeAdapter string_adapter; + private volatile TypeAdapter boundingBox_adapter; + private volatile TypeAdapter> list__geometry_adapter; + private final Gson gson; + public GsonTypeAdapter(Gson gson) { + this.gson = gson; + } + @Override + @SuppressWarnings("unchecked") + public void write(JsonWriter jsonWriter, GeometryCollection object) throws IOException { + if (object == null) { + jsonWriter.nullValue(); + return; + } + jsonWriter.beginObject(); + jsonWriter.name("type"); + if (object.type() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + string_adapter.write(jsonWriter, object.type()); + } + jsonWriter.name("bbox"); + if (object.bbox() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + boundingBox_adapter.write(jsonWriter, object.bbox()); + } + jsonWriter.name("geometries"); + if (object.geometries() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter> list__geometry_adapter = this.list__geometry_adapter; + if (list__geometry_adapter == null) { + this.list__geometry_adapter = list__geometry_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Geometry.class)); + } + list__geometry_adapter.write(jsonWriter, object.geometries()); + } + jsonWriter.endObject(); + } + @Override + @SuppressWarnings("unchecked") + public GeometryCollection read(JsonReader jsonReader) throws IOException { + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + return null; + } + jsonReader.beginObject(); + String type = null; + BoundingBox bbox = null; + List geometries = null; + while (jsonReader.hasNext()) { + String _name = jsonReader.nextName(); + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + continue; + } + switch (_name) { + case "type": { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + type = string_adapter.read(jsonReader); + break; + } + case "bbox": { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + bbox = boundingBox_adapter.read(jsonReader); + break; + } + case "geometries": { + TypeAdapter> list__geometry_adapter = this.list__geometry_adapter; + if (list__geometry_adapter == null) { + this.list__geometry_adapter = list__geometry_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Geometry.class)); + } + geometries = list__geometry_adapter.read(jsonReader); + break; + } + default: { + jsonReader.skipValue(); + } + } + } + jsonReader.endObject(); + return new GeometryCollection(type == null ? "GeometryCollection" : type, bbox, geometries); + } } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/LineString.java b/services-geojson/src/main/java/com/mapbox/geojson/LineString.java index d0280378d..38c2466f4 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/LineString.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/LineString.java @@ -2,10 +2,13 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.google.auto.value.AutoValue; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; import com.mapbox.geojson.gson.BoundingBoxDeserializer; import com.mapbox.geojson.gson.BoundingBoxSerializer; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; @@ -13,6 +16,7 @@ import com.mapbox.geojson.gson.PointSerializer; import com.mapbox.geojson.utils.PolylineUtils; +import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -50,11 +54,16 @@ * * @since 1.0.0 */ -@AutoValue -public abstract class LineString implements CoordinateContainer>, Serializable { +public final class LineString implements CoordinateContainer>, Serializable { private static final String TYPE = "LineString"; + private final String type; + + private final BoundingBox bbox; + + private final List coordinates; + /** * Create a new instance of this class by passing in a formatted valid JSON String. If you are * creating a LineString object from scratch it is better to use one of the other provided static @@ -85,7 +94,7 @@ public static LineString fromJson(String json) { * @since 3.0.0 */ public static LineString fromLngLats(@NonNull MultiPoint multiPoint) { - return new AutoValue_LineString(TYPE, null, multiPoint.coordinates()); + return new LineString(TYPE, null, multiPoint.coordinates()); } /** @@ -103,7 +112,7 @@ public static LineString fromLngLats(@NonNull MultiPoint multiPoint) { * @since 3.0.0 */ public static LineString fromLngLats(@NonNull List points) { - return new AutoValue_LineString(TYPE, null, points); + return new LineString(TYPE, null, points); } /** @@ -122,7 +131,7 @@ public static LineString fromLngLats(@NonNull List points) { * @since 3.0.0 */ public static LineString fromLngLats(@NonNull List points, @Nullable BoundingBox bbox) { - return new AutoValue_LineString(TYPE, bbox, points); + return new LineString(TYPE, bbox, points); } /** @@ -136,7 +145,19 @@ public static LineString fromLngLats(@NonNull List points, @Nullable Boun * @since 3.0.0 */ public static LineString fromLngLats(@NonNull MultiPoint multiPoint, @Nullable BoundingBox bbox) { - return new AutoValue_LineString(TYPE, bbox, multiPoint.coordinates()); + return new LineString(TYPE, bbox, multiPoint.coordinates()); + } + + LineString(String type, @Nullable BoundingBox bbox, List coordinates) { + if (type == null) { + throw new NullPointerException("Null type"); + } + this.type = type; + this.bbox = bbox; + if (coordinates == null) { + throw new NullPointerException("Null coordinates"); + } + this.coordinates = coordinates; } static LineString fromLngLats(double[][] coordinates) { @@ -175,7 +196,9 @@ public static LineString fromPolyline(@NonNull String polyline, int precision) { */ @NonNull @Override - public abstract String type(); + public String type() { + return type; + } /** * A Feature Collection might have a member named {@code bbox} to include information on the @@ -189,7 +212,9 @@ public static LineString fromPolyline(@NonNull String polyline, int precision) { */ @Nullable @Override - public abstract BoundingBox bbox(); + public BoundingBox bbox() { + return bbox; + } /** * Provides the list of {@link Point}s that make up the LineString geometry. @@ -199,7 +224,9 @@ public static LineString fromPolyline(@NonNull String polyline, int precision) { */ @NonNull @Override - public abstract List coordinates(); + public List coordinates() { + return coordinates; + } /** * This takes the currently defined values found inside this instance and converts it to a GeoJson @@ -237,6 +264,141 @@ public String toPolyline(int precision) { * @since 3.0.0 */ public static TypeAdapter typeAdapter(Gson gson) { - return new AutoValue_LineString.GsonTypeAdapter(gson); + return new LineString.GsonTypeAdapter(gson); + } + + @Override + public String toString() { + return "LineString{" + + "type=" + type + ", " + + "bbox=" + bbox + ", " + + "coordinates=" + coordinates + + "}"; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof LineString) { + LineString that = (LineString) o; + return (this.type.equals(that.type())) + && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) + && (this.coordinates.equals(that.coordinates())); + } + return false; + } + + @Override + public int hashCode() { + int h$ = 1; + h$ *= 1000003; + h$ ^= type.hashCode(); + h$ *= 1000003; + h$ ^= (bbox == null) ? 0 : bbox.hashCode(); + h$ *= 1000003; + h$ ^= coordinates.hashCode(); + return h$; + } + + public static final class GsonTypeAdapter extends TypeAdapter { + private volatile TypeAdapter string_adapter; + private volatile TypeAdapter boundingBox_adapter; + private volatile TypeAdapter> list__point_adapter; + private final Gson gson; + public GsonTypeAdapter(Gson gson) { + this.gson = gson; + } + @Override + @SuppressWarnings("unchecked") + public void write(JsonWriter jsonWriter, LineString object) throws IOException { + if (object == null) { + jsonWriter.nullValue(); + return; + } + jsonWriter.beginObject(); + jsonWriter.name("type"); + if (object.type() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + string_adapter.write(jsonWriter, object.type()); + } + jsonWriter.name("bbox"); + if (object.bbox() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + boundingBox_adapter.write(jsonWriter, object.bbox()); + } + jsonWriter.name("coordinates"); + if (object.coordinates() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter> list__point_adapter = this.list__point_adapter; + if (list__point_adapter == null) { + this.list__point_adapter = list__point_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Point.class)); + } + list__point_adapter.write(jsonWriter, object.coordinates()); + } + jsonWriter.endObject(); + } + @Override + @SuppressWarnings("unchecked") + public LineString read(JsonReader jsonReader) throws IOException { + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + return null; + } + jsonReader.beginObject(); + String type = null; + BoundingBox bbox = null; + List coordinates = null; + while (jsonReader.hasNext()) { + String _name = jsonReader.nextName(); + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + continue; + } + switch (_name) { + case "type": { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + type = string_adapter.read(jsonReader); + break; + } + case "bbox": { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + bbox = boundingBox_adapter.read(jsonReader); + break; + } + case "coordinates": { + TypeAdapter> list__point_adapter = this.list__point_adapter; + if (list__point_adapter == null) { + this.list__point_adapter = list__point_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Point.class)); + } + coordinates = list__point_adapter.read(jsonReader); + break; + } + default: { + jsonReader.skipValue(); + } + } + } + jsonReader.endObject(); + return new LineString(type == null ? "LineString" : type, bbox, coordinates); + } } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/MultiLineString.java b/services-geojson/src/main/java/com/mapbox/geojson/MultiLineString.java index 0505f88fe..e05475941 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/MultiLineString.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/MultiLineString.java @@ -2,15 +2,20 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.google.auto.value.AutoValue; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.mapbox.geojson.gson.BoundingBoxDeserializer; import com.mapbox.geojson.gson.BoundingBoxSerializer; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; import com.mapbox.geojson.gson.PointDeserializer; import com.mapbox.geojson.gson.PointSerializer; +import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; @@ -50,12 +55,17 @@ * * @since 1.0.0 */ -@AutoValue -public abstract class MultiLineString +public final class MultiLineString implements CoordinateContainer>>, Serializable { private static final String TYPE = "MultiLineString"; + private final String type; + + private final BoundingBox bbox; + + private final List> coordinates; + /** * Create a new instance of this class by passing in a formatted valid JSON String. If you are * creating a MultiLineString object from scratch it is better to use one of the other provided @@ -70,6 +80,7 @@ public static MultiLineString fromJson(@NonNull String json) { GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); gson.registerTypeAdapter(Point.class, new PointDeserializer()); + gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); return gson.create().fromJson(json, MultiLineString.class); } @@ -88,7 +99,7 @@ public static MultiLineString fromLineStrings(@NonNull List lineStri for (LineString lineString : lineStrings) { coordinates.add(lineString.coordinates()); } - return new AutoValue_MultiLineString(TYPE, null, coordinates); + return new MultiLineString(TYPE, null, coordinates); } /** @@ -109,7 +120,7 @@ public static MultiLineString fromLineStrings(@NonNull List lineStri for (LineString lineString : lineStrings) { coordinates.add(lineString.coordinates()); } - return new AutoValue_MultiLineString(TYPE, bbox, coordinates); + return new MultiLineString(TYPE, bbox, coordinates); } /** @@ -123,7 +134,7 @@ public static MultiLineString fromLineStrings(@NonNull List lineStri */ public static MultiLineString fromLineString(@NonNull LineString lineString) { List> coordinates = Arrays.asList(lineString.coordinates()); - return new AutoValue_MultiLineString(TYPE, null, coordinates); + return new MultiLineString(TYPE, null, coordinates); } /** @@ -139,7 +150,7 @@ public static MultiLineString fromLineString(@NonNull LineString lineString) { public static MultiLineString fromLineString(@NonNull LineString lineString, @Nullable BoundingBox bbox) { List> coordinates = Arrays.asList(lineString.coordinates()); - return new AutoValue_MultiLineString(TYPE, bbox, coordinates); + return new MultiLineString(TYPE, bbox, coordinates); } /** @@ -154,7 +165,7 @@ public static MultiLineString fromLineString(@NonNull LineString lineString, * @since 3.0.0 */ public static MultiLineString fromLngLats(@NonNull List> points) { - return new AutoValue_MultiLineString(TYPE, null, points); + return new MultiLineString(TYPE, null, points); } /** @@ -171,7 +182,7 @@ public static MultiLineString fromLngLats(@NonNull List> points) { */ public static MultiLineString fromLngLats(@NonNull List> points, @Nullable BoundingBox bbox) { - return new AutoValue_MultiLineString(TYPE, bbox, points); + return new MultiLineString(TYPE, bbox, points); } static MultiLineString fromLngLats(double[][][] coordinates) { @@ -184,7 +195,19 @@ static MultiLineString fromLngLats(double[][][] coordinates) { multiLine.add(lineString); } - return new AutoValue_MultiLineString(TYPE, null, multiLine); + return new MultiLineString(TYPE, null, multiLine); + } + + MultiLineString(String type, @Nullable BoundingBox bbox, List> coordinates) { + if (type == null) { + throw new NullPointerException("Null type"); + } + this.type = type; + this.bbox = bbox; + if (coordinates == null) { + throw new NullPointerException("Null coordinates"); + } + this.coordinates = coordinates; } /** @@ -197,7 +220,9 @@ static MultiLineString fromLngLats(double[][][] coordinates) { */ @NonNull @Override - public abstract String type(); + public String type() { + return type; + } /** * A Feature Collection might have a member named {@code bbox} to include information on the @@ -211,7 +236,9 @@ static MultiLineString fromLngLats(double[][][] coordinates) { */ @Nullable @Override - public abstract BoundingBox bbox(); + public BoundingBox bbox() { + return bbox; + } /** * Provides the list of list of {@link Point}s that make up the MultiLineString geometry. @@ -221,7 +248,9 @@ static MultiLineString fromLngLats(double[][][] coordinates) { */ @NonNull @Override - public abstract List> coordinates(); + public List> coordinates() { + return coordinates; + } /** * Returns a list of LineStrings which are currently making up this MultiLineString. @@ -261,6 +290,141 @@ public String toJson() { * @since 3.0.0 */ public static TypeAdapter typeAdapter(Gson gson) { - return new AutoValue_MultiLineString.GsonTypeAdapter(gson); + return new MultiLineString.GsonTypeAdapter(gson); + } + + @Override + public String toString() { + return "MultiLineString{" + + "type=" + type + ", " + + "bbox=" + bbox + ", " + + "coordinates=" + coordinates + + "}"; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof MultiLineString) { + MultiLineString that = (MultiLineString) o; + return (this.type.equals(that.type())) + && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) + && (this.coordinates.equals(that.coordinates())); + } + return false; + } + + @Override + public int hashCode() { + int h$ = 1; + h$ *= 1000003; + h$ ^= type.hashCode(); + h$ *= 1000003; + h$ ^= (bbox == null) ? 0 : bbox.hashCode(); + h$ *= 1000003; + h$ ^= coordinates.hashCode(); + return h$; + } + + public static final class GsonTypeAdapter extends TypeAdapter { + private volatile TypeAdapter string_adapter; + private volatile TypeAdapter boundingBox_adapter; + private volatile TypeAdapter>> list__list__point_adapter; + private final Gson gson; + public GsonTypeAdapter(Gson gson) { + this.gson = gson; + } + @Override + @SuppressWarnings("unchecked") + public void write(JsonWriter jsonWriter, MultiLineString object) throws IOException { + if (object == null) { + jsonWriter.nullValue(); + return; + } + jsonWriter.beginObject(); + jsonWriter.name("type"); + if (object.type() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + string_adapter.write(jsonWriter, object.type()); + } + jsonWriter.name("bbox"); + if (object.bbox() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + boundingBox_adapter.write(jsonWriter, object.bbox()); + } + jsonWriter.name("coordinates"); + if (object.coordinates() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter>> list__list__point_adapter = this.list__list__point_adapter; + if (list__list__point_adapter == null) { + this.list__list__point_adapter = list__list__point_adapter = (TypeAdapter>>) gson.getAdapter(TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, Point.class).getType())); + } + list__list__point_adapter.write(jsonWriter, object.coordinates()); + } + jsonWriter.endObject(); + } + @Override + @SuppressWarnings("unchecked") + public MultiLineString read(JsonReader jsonReader) throws IOException { + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + return null; + } + jsonReader.beginObject(); + String type = null; + BoundingBox bbox = null; + List> coordinates = null; + while (jsonReader.hasNext()) { + String _name = jsonReader.nextName(); + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + continue; + } + switch (_name) { + case "type": { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + type = string_adapter.read(jsonReader); + break; + } + case "bbox": { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + bbox = boundingBox_adapter.read(jsonReader); + break; + } + case "coordinates": { + TypeAdapter>> list__list__point_adapter = this.list__list__point_adapter; + if (list__list__point_adapter == null) { + this.list__list__point_adapter = list__list__point_adapter = (TypeAdapter>>) gson.getAdapter(TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, Point.class).getType())); + } + coordinates = list__list__point_adapter.read(jsonReader); + break; + } + default: { + jsonReader.skipValue(); + } + } + } + jsonReader.endObject(); + return new MultiLineString(type, bbox, coordinates); + } } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/MultiPoint.java b/services-geojson/src/main/java/com/mapbox/geojson/MultiPoint.java index dd145f808..a3c754ec0 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/MultiPoint.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/MultiPoint.java @@ -2,15 +2,20 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.google.auto.value.AutoValue; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.mapbox.geojson.gson.BoundingBoxDeserializer; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; import com.mapbox.geojson.gson.PointDeserializer; import com.mapbox.geojson.gson.BoundingBoxSerializer; import com.mapbox.geojson.gson.PointSerializer; +import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -35,11 +40,16 @@ * * @since 1.0.0 */ -@AutoValue -public abstract class MultiPoint implements CoordinateContainer>, Serializable { +public final class MultiPoint implements CoordinateContainer>, Serializable { private static final String TYPE = "MultiPoint"; + private final String type; + + private final BoundingBox bbox; + + private final List coordinates; + /** * Create a new instance of this class by passing in a formatted valid JSON String. If you are * creating a MultiPoint object from scratch it is better to use one of the other provided static @@ -55,6 +65,7 @@ public static MultiPoint fromJson(@NonNull String json) { GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); gson.registerTypeAdapter(Point.class, new PointDeserializer()); + gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); return gson.create().fromJson(json, MultiPoint.class); } @@ -70,7 +81,7 @@ public static MultiPoint fromJson(@NonNull String json) { * @since 3.0.0 */ public static MultiPoint fromLngLats(@NonNull List points) { - return new AutoValue_MultiPoint(TYPE, null, points); + return new MultiPoint(TYPE, null, points); } /** @@ -86,7 +97,7 @@ public static MultiPoint fromLngLats(@NonNull List points) { * @since 3.0.0 */ public static MultiPoint fromLngLats(@NonNull List points, @Nullable BoundingBox bbox) { - return new AutoValue_MultiPoint(TYPE, bbox, points); + return new MultiPoint(TYPE, bbox, points); } static MultiPoint fromLngLats(@NonNull double[][] coordinates) { @@ -95,7 +106,19 @@ static MultiPoint fromLngLats(@NonNull double[][] coordinates) { converted.add(Point.fromLngLat(coordinates[i])); } - return new AutoValue_MultiPoint(TYPE, null, converted); + return new MultiPoint(TYPE, null, converted); + } + + MultiPoint(String type, @Nullable BoundingBox bbox, List coordinates) { + if (type == null) { + throw new NullPointerException("Null type"); + } + this.type = type; + this.bbox = bbox; + if (coordinates == null) { + throw new NullPointerException("Null coordinates"); + } + this.coordinates = coordinates; } /** @@ -108,7 +131,9 @@ static MultiPoint fromLngLats(@NonNull double[][] coordinates) { */ @NonNull @Override - public abstract String type(); + public String type() { + return type; + } /** * A Feature Collection might have a member named {@code bbox} to include information on the @@ -122,7 +147,7 @@ static MultiPoint fromLngLats(@NonNull double[][] coordinates) { */ @Nullable @Override - public abstract BoundingBox bbox(); + public BoundingBox bbox() { return bbox; } /** * provides the list of {@link Point}s that make up the MultiPoint geometry. @@ -132,7 +157,9 @@ static MultiPoint fromLngLats(@NonNull double[][] coordinates) { */ @NonNull @Override - public abstract List coordinates(); + public List coordinates() { + return coordinates; + } /** * This takes the currently defined values found inside this instance and converts it to a GeoJson @@ -157,6 +184,141 @@ public String toJson() { * @since 3.0.0 */ public static TypeAdapter typeAdapter(Gson gson) { - return new AutoValue_MultiPoint.GsonTypeAdapter(gson); + return new MultiPoint.GsonTypeAdapter(gson); + } + + @Override + public String toString() { + return "MultiPoint{" + + "type=" + type + ", " + + "bbox=" + bbox + ", " + + "coordinates=" + coordinates + + "}"; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof MultiPoint) { + MultiPoint that = (MultiPoint) o; + return (this.type.equals(that.type())) + && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) + && (this.coordinates.equals(that.coordinates())); + } + return false; + } + + @Override + public int hashCode() { + int h$ = 1; + h$ *= 1000003; + h$ ^= type.hashCode(); + h$ *= 1000003; + h$ ^= (bbox == null) ? 0 : bbox.hashCode(); + h$ *= 1000003; + h$ ^= coordinates.hashCode(); + return h$; + } + + public static final class GsonTypeAdapter extends TypeAdapter { + private volatile TypeAdapter string_adapter; + private volatile TypeAdapter boundingBox_adapter; + private volatile TypeAdapter> list__point_adapter; + private final Gson gson; + public GsonTypeAdapter(Gson gson) { + this.gson = gson; + } + @Override + @SuppressWarnings("unchecked") + public void write(JsonWriter jsonWriter, MultiPoint object) throws IOException { + if (object == null) { + jsonWriter.nullValue(); + return; + } + jsonWriter.beginObject(); + jsonWriter.name("type"); + if (object.type() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + string_adapter.write(jsonWriter, object.type()); + } + jsonWriter.name("bbox"); + if (object.bbox() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + boundingBox_adapter.write(jsonWriter, object.bbox()); + } + jsonWriter.name("coordinates"); + if (object.coordinates() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter> list__point_adapter = this.list__point_adapter; + if (list__point_adapter == null) { + this.list__point_adapter = list__point_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Point.class)); + } + list__point_adapter.write(jsonWriter, object.coordinates()); + } + jsonWriter.endObject(); + } + @Override + @SuppressWarnings("unchecked") + public MultiPoint read(JsonReader jsonReader) throws IOException { + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + return null; + } + jsonReader.beginObject(); + String type = null; + BoundingBox bbox = null; + List coordinates = null; + while (jsonReader.hasNext()) { + String _name = jsonReader.nextName(); + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + continue; + } + switch (_name) { + case "type": { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + type = string_adapter.read(jsonReader); + break; + } + case "bbox": { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + bbox = boundingBox_adapter.read(jsonReader); + break; + } + case "coordinates": { + TypeAdapter> list__point_adapter = this.list__point_adapter; + if (list__point_adapter == null) { + this.list__point_adapter = list__point_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Point.class)); + } + coordinates = list__point_adapter.read(jsonReader); + break; + } + default: { + jsonReader.skipValue(); + } + } + } + jsonReader.endObject(); + return new MultiPoint(type, bbox, coordinates); + } } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/MultiPolygon.java b/services-geojson/src/main/java/com/mapbox/geojson/MultiPolygon.java index 2eeb703c3..95ae5cb76 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/MultiPolygon.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/MultiPolygon.java @@ -2,15 +2,20 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.google.auto.value.AutoValue; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.mapbox.geojson.gson.BoundingBoxDeserializer; import com.mapbox.geojson.gson.BoundingBoxSerializer; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; import com.mapbox.geojson.gson.PointDeserializer; import com.mapbox.geojson.gson.PointSerializer; +import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; @@ -68,12 +73,17 @@ * * @since 1.0.0 */ -@AutoValue -public abstract class MultiPolygon +public final class MultiPolygon implements CoordinateContainer>>>, Serializable { private static final String TYPE = "MultiPolygon"; + private final String type; + + private final BoundingBox bbox; + + private final List>> coordinates; + /** * Create a new instance of this class by passing in a formatted valid JSON String. If you are * creating a MultiPolygon object from scratch it is better to use one of the other provided @@ -88,6 +98,7 @@ public static MultiPolygon fromJson(String json) { GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); gson.registerTypeAdapter(Point.class, new PointDeserializer()); + gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); return gson.create().fromJson(json, MultiPolygon.class); } @@ -106,7 +117,7 @@ public static MultiPolygon fromPolygons(@NonNull List polygons) { for (Polygon polygon : polygons) { coordinates.add(polygon.coordinates()); } - return new AutoValue_MultiPolygon(TYPE, null, coordinates); + return new MultiPolygon(TYPE, null, coordinates); } /** @@ -127,7 +138,7 @@ public static MultiPolygon fromPolygons(@NonNull List polygons, for (Polygon polygon : polygons) { coordinates.add(polygon.coordinates()); } - return new AutoValue_MultiPolygon(TYPE, bbox, coordinates); + return new MultiPolygon(TYPE, bbox, coordinates); } /** @@ -142,7 +153,7 @@ public static MultiPolygon fromPolygons(@NonNull List polygons, */ public static MultiPolygon fromPolygon(@NonNull Polygon polygon) { List>> coordinates = Arrays.asList(polygon.coordinates()); - return new AutoValue_MultiPolygon(TYPE, null, coordinates); + return new MultiPolygon(TYPE, null, coordinates); } /** @@ -158,7 +169,7 @@ public static MultiPolygon fromPolygon(@NonNull Polygon polygon) { */ public static MultiPolygon fromPolygon(@NonNull Polygon polygon, @Nullable BoundingBox bbox) { List>> coordinates = Arrays.asList(polygon.coordinates()); - return new AutoValue_MultiPolygon(TYPE, bbox, coordinates); + return new MultiPolygon(TYPE, bbox, coordinates); } /** @@ -171,7 +182,7 @@ public static MultiPolygon fromPolygon(@NonNull Polygon polygon, @Nullable Bound * @since 3.0.0 */ public static MultiPolygon fromLngLats(@NonNull List>> points) { - return new AutoValue_MultiPolygon(TYPE, null, points); + return new MultiPolygon(TYPE, null, points); } /** @@ -186,7 +197,7 @@ public static MultiPolygon fromLngLats(@NonNull List>> points) */ public static MultiPolygon fromLngLats(@NonNull List>> points, @Nullable BoundingBox bbox) { - return new AutoValue_MultiPolygon(TYPE, bbox, points); + return new MultiPolygon(TYPE, bbox, points); } static MultiPolygon fromLngLats(@NonNull double[][][][] coordinates) { @@ -203,7 +214,19 @@ static MultiPolygon fromLngLats(@NonNull double[][][][] coordinates) { converted.add(innerOneList); } - return new AutoValue_MultiPolygon(TYPE, null, converted); + return new MultiPolygon(TYPE, null, converted); + } + + MultiPolygon(String type, @Nullable BoundingBox bbox, List>> coordinates) { + if (type == null) { + throw new NullPointerException("Null type"); + } + this.type = type; + this.bbox = bbox; + if (coordinates == null) { + throw new NullPointerException("Null coordinates"); + } + this.coordinates = coordinates; } /** @@ -231,7 +254,9 @@ public List polygons() { */ @NonNull @Override - public abstract String type(); + public String type() { + return type; + } /** * A Feature Collection might have a member named {@code bbox} to include information on the @@ -245,7 +270,9 @@ public List polygons() { */ @Nullable @Override - public abstract BoundingBox bbox(); + public BoundingBox bbox() { + return bbox; + } /** * Provides the list of list of list of {@link Point}s that make up the MultiPolygon geometry. @@ -255,7 +282,9 @@ public List polygons() { */ @NonNull @Override - public abstract List>> coordinates(); + public List>> coordinates() { + return coordinates; + } /** * This takes the currently defined values found inside this instance and converts it to a GeoJson @@ -280,6 +309,141 @@ public String toJson() { * @since 3.0.0 */ public static TypeAdapter typeAdapter(Gson gson) { - return new AutoValue_MultiPolygon.GsonTypeAdapter(gson); + return new MultiPolygon.GsonTypeAdapter(gson); + } + + @Override + public String toString() { + return "Polygon{" + + "type=" + type + ", " + + "bbox=" + bbox + ", " + + "coordinates=" + coordinates + + "}"; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof MultiPolygon) { + MultiPolygon that = (MultiPolygon) o; + return (this.type.equals(that.type())) + && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) + && (this.coordinates.equals(that.coordinates())); + } + return false; + } + + @Override + public int hashCode() { + int h$ = 1; + h$ *= 1000003; + h$ ^= type.hashCode(); + h$ *= 1000003; + h$ ^= (bbox == null) ? 0 : bbox.hashCode(); + h$ *= 1000003; + h$ ^= coordinates.hashCode(); + return h$; + } + + public static final class GsonTypeAdapter extends TypeAdapter { + private volatile TypeAdapter string_adapter; + private volatile TypeAdapter boundingBox_adapter; + private volatile TypeAdapter>>> list__list__list__point_adapter; + private final Gson gson; + public GsonTypeAdapter(Gson gson) { + this.gson = gson; + } + @Override + @SuppressWarnings("unchecked") + public void write(JsonWriter jsonWriter, MultiPolygon object) throws IOException { + if (object == null) { + jsonWriter.nullValue(); + return; + } + jsonWriter.beginObject(); + jsonWriter.name("type"); + if (object.type() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + string_adapter.write(jsonWriter, object.type()); + } + jsonWriter.name("bbox"); + if (object.bbox() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + boundingBox_adapter.write(jsonWriter, object.bbox()); + } + jsonWriter.name("coordinates"); + if (object.coordinates() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter>>> list__list__list__point_adapter = this.list__list__list__point_adapter; + if (list__list__list__point_adapter == null) { + this.list__list__list__point_adapter = list__list__list__point_adapter = (TypeAdapter>>>) gson.getAdapter(TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, Point.class).getType()).getType())); + } + list__list__list__point_adapter.write(jsonWriter, object.coordinates()); + } + jsonWriter.endObject(); + } + @Override + @SuppressWarnings("unchecked") + public MultiPolygon read(JsonReader jsonReader) throws IOException { + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + return null; + } + jsonReader.beginObject(); + String type = null; + BoundingBox bbox = null; + List>> coordinates = null; + while (jsonReader.hasNext()) { + String _name = jsonReader.nextName(); + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + continue; + } + switch (_name) { + case "type": { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + type = string_adapter.read(jsonReader); + break; + } + case "bbox": { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + bbox = boundingBox_adapter.read(jsonReader); + break; + } + case "coordinates": { + TypeAdapter>>> list__list__list__point_adapter = this.list__list__list__point_adapter; + if (list__list__list__point_adapter == null) { + this.list__list__list__point_adapter = list__list__list__point_adapter = (TypeAdapter>>>) gson.getAdapter(TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, Point.class).getType()).getType())); + } + coordinates = list__list__list__point_adapter.read(jsonReader); + break; + } + default: { + jsonReader.skipValue(); + } + } + } + jsonReader.endObject(); + return new MultiPolygon(type, bbox, coordinates); + } } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/Point.java b/services-geojson/src/main/java/com/mapbox/geojson/Point.java index e9cb1990b..cb2eaf4e1 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/Point.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/Point.java @@ -8,17 +8,23 @@ import android.support.annotation.FloatRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.google.auto.value.AutoValue; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; import com.mapbox.geojson.gson.BoundingBoxDeserializer; import com.mapbox.geojson.gson.BoundingBoxSerializer; import com.mapbox.geojson.gson.CoordinateTypeAdapter; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; +import com.mapbox.geojson.gson.GeometryTypeAdapter; +import com.mapbox.geojson.gson.PointDeserializer; +import com.mapbox.geojson.gson.PointSerializer; import com.mapbox.geojson.shifter.CoordinateShifterManager; +import java.io.IOException; import java.io.Serializable; import java.util.List; @@ -53,11 +59,16 @@ * * @since 1.0.0 */ -@AutoValue -public abstract class Point implements CoordinateContainer>, Serializable { +public final class Point implements CoordinateContainer>, Serializable { private static final String TYPE = "Point"; + private final String type; + + private final BoundingBox bbox; + + private final List coordinates; + /** * Create a new instance of this class by passing in a formatted valid JSON String. If you are * creating a Point object from scratch it is better to use one of the other provided static @@ -73,7 +84,7 @@ public abstract class Point implements CoordinateContainer>, Serial */ public static Point fromJson(@NonNull String json) { GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); + gson.registerTypeAdapter(Point.class, new PointDeserializer()); gson.registerTypeAdapter(new TypeToken>(){}.getType(), new CoordinateTypeAdapter()); gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); @@ -99,7 +110,7 @@ public static Point fromLngLat( List coordinates = CoordinateShifterManager.getCoordinateShifter().shiftLonLat(longitude, latitude); - return new AutoValue_Point(TYPE, null, coordinates); + return new Point(TYPE, null, coordinates); } /** @@ -124,7 +135,7 @@ public static Point fromLngLat( List coordinates = CoordinateShifterManager.getCoordinateShifter().shiftLonLat(longitude, latitude); - return new AutoValue_Point(TYPE, bbox, coordinates); + return new Point(TYPE, bbox, coordinates); } /** @@ -151,7 +162,7 @@ public static Point fromLngLat( List coordinates = CoordinateShifterManager.getCoordinateShifter().shiftLonLatAlt(longitude, latitude, altitude); - return new AutoValue_Point(TYPE, null, coordinates); + return new Point(TYPE, null, coordinates); } /** @@ -178,7 +189,7 @@ public static Point fromLngLat( List coordinates = CoordinateShifterManager.getCoordinateShifter().shiftLonLatAlt(longitude, latitude, altitude); - return new AutoValue_Point(TYPE, bbox, coordinates); + return new Point(TYPE, bbox, coordinates); } static Point fromLngLat(@NonNull double[] coords) { @@ -191,6 +202,18 @@ static Point fromLngLat(@NonNull double[] coords) { return null; } + Point(String type, @Nullable BoundingBox bbox, List coordinates) { + if (type == null) { + throw new NullPointerException("Null type"); + } + this.type = type; + this.bbox = bbox; + if (coordinates == null) { + throw new NullPointerException("Null coordinates"); + } + this.coordinates = coordinates; + } + /** * This returns a double value ranging from -180 to 180 representing the x or easting position of * this point. ideally, this value would be restricted to 6 decimal places to correctly follow the @@ -255,7 +278,9 @@ public boolean hasAltitude() { */ @NonNull @Override - public abstract String type(); + public String type() { + return type; + } /** * A Feature Collection might have a member named {@code bbox} to include information on the @@ -269,7 +294,9 @@ public boolean hasAltitude() { */ @Nullable @Override - public abstract BoundingBox bbox(); + public BoundingBox bbox() { + return bbox; + } /** * Provide a single double array containing the longitude, latitude, and optionally an @@ -281,7 +308,9 @@ public boolean hasAltitude() { */ @NonNull @Override - public abstract List coordinates(); + public List coordinates() { + return coordinates; + } /** * This takes the currently defined values found inside this instance and converts it to a GeoJson @@ -293,6 +322,7 @@ public boolean hasAltitude() { @Override public String toJson() { GsonBuilder gson = new GsonBuilder(); + gson.registerTypeAdapter(Geometry.class, new GeometryTypeAdapter()); gson.registerTypeAdapter(new TypeToken>(){}.getType(), new CoordinateTypeAdapter()); gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()); @@ -307,6 +337,144 @@ public String toJson() { * @since 3.0.0 */ public static TypeAdapter typeAdapter(Gson gson) { - return new AutoValue_Point.GsonTypeAdapter(gson); + return new Point.GsonTypeAdapter(gson); + } + + @Override + public String toString() { +// return "Point{" +// + "type=" + type + ", " +// + "bbox=" + bbox + ", " +// + "coordinates=" + coordinates +// + "}"; + return "" + coordinates; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof Point) { + Point that = (Point) o; + return (this.type.equals(that.type())) + && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) + && (this.coordinates.equals(that.coordinates())); + } + return false; + } + + @Override + public int hashCode() { + int h$ = 1; + h$ *= 1000003; + h$ ^= type.hashCode(); + h$ *= 1000003; + h$ ^= (bbox == null) ? 0 : bbox.hashCode(); + h$ *= 1000003; + h$ ^= coordinates.hashCode(); + return h$; + } + + public static final class GsonTypeAdapter extends TypeAdapter { + private volatile TypeAdapter string_adapter; + private volatile TypeAdapter boundingBox_adapter; + private volatile TypeAdapter> list__double_adapter; + private final Gson gson; + public GsonTypeAdapter(Gson gson) { + this.gson = gson; + } + @Override + @SuppressWarnings("unchecked") + public void write(JsonWriter jsonWriter, Point object) throws IOException { + if (object == null) { + jsonWriter.nullValue(); + return; + } + jsonWriter.beginObject(); + jsonWriter.name("type"); + if (object.type() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + string_adapter.write(jsonWriter, object.type()); + } + jsonWriter.name("bbox"); + if (object.bbox() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + boundingBox_adapter.write(jsonWriter, object.bbox()); + } + jsonWriter.name("coordinates"); + if (object.coordinates() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter> list__double_adapter = this.list__double_adapter; + if (list__double_adapter == null) { + this.list__double_adapter = list__double_adapter = + (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Double.class)); + } + list__double_adapter.write(jsonWriter, object.coordinates()); + } + jsonWriter.endObject(); + } + @Override + @SuppressWarnings("unchecked") + public Point read(JsonReader jsonReader) throws IOException { + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + return null; + } + jsonReader.beginObject(); + String type = null; + BoundingBox bbox = null; + List coordinates = null; + while (jsonReader.hasNext()) { + String _name = jsonReader.nextName(); + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + continue; + } + switch (_name) { + case "type": { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + type = string_adapter.read(jsonReader); + break; + } + case "bbox": { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + bbox = boundingBox_adapter.read(jsonReader); + break; + } + case "coordinates": { + TypeAdapter> list__double_adapter = this.list__double_adapter; + if (list__double_adapter == null) { + this.list__double_adapter = list__double_adapter = + (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Double.class)); + } + coordinates = list__double_adapter.read(jsonReader); + break; + } + default: { + jsonReader.skipValue(); + } + } + } + jsonReader.endObject(); + return new Point(type == null ? "Point" : type, bbox, coordinates); + } } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/Polygon.java b/services-geojson/src/main/java/com/mapbox/geojson/Polygon.java index b0150d424..580b1f484 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/Polygon.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/Polygon.java @@ -4,10 +4,13 @@ import android.support.annotation.Nullable; import android.support.annotation.Size; -import com.google.auto.value.AutoValue; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; import com.mapbox.geojson.exception.GeoJsonException; import com.mapbox.geojson.gson.BoundingBoxDeserializer; @@ -16,6 +19,7 @@ import com.mapbox.geojson.gson.BoundingBoxSerializer; import com.mapbox.geojson.gson.PointSerializer; +import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -58,11 +62,16 @@ * * @since 1.0.0 */ -@AutoValue -public abstract class Polygon implements CoordinateContainer>>, Serializable { +public final class Polygon implements CoordinateContainer>>, Serializable { private static final String TYPE = "Polygon"; + private final String type; + + private final BoundingBox bbox; + + private final List> coordinates; + /** * Create a new instance of this class by passing in a formatted valid JSON String. If you are * creating a Polygon object from scratch it is better to use one of the other provided static @@ -79,7 +88,6 @@ public static Polygon fromJson(@NonNull String json) { GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); gson.registerTypeAdapter(Point.class, new PointDeserializer()); - gson.registerTypeAdapter(Geometry.class, new GeometryDeserializer()); gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); return gson.create().fromJson(json, Polygon.class); } @@ -95,7 +103,7 @@ public static Polygon fromJson(@NonNull String json) { * @since 3.0.0 */ public static Polygon fromLngLats(@NonNull List> coordinates) { - return new AutoValue_Polygon(TYPE, null, coordinates); + return new Polygon(TYPE, null, coordinates); } /** @@ -111,7 +119,7 @@ public static Polygon fromLngLats(@NonNull List> coordinates) { */ public static Polygon fromLngLats(@NonNull List> coordinates, @Nullable BoundingBox bbox) { - return new AutoValue_Polygon(TYPE, bbox, coordinates); + return new Polygon(TYPE, bbox, coordinates); } /** @@ -132,7 +140,7 @@ static Polygon fromLngLats(@NonNull double[][][] coordinates) { } converted.add(innerList); } - return new AutoValue_Polygon(TYPE, null, converted); + return new Polygon(TYPE, null, converted); } /** @@ -154,13 +162,13 @@ public static Polygon fromOuterInner(@NonNull LineString outer, @Nullable LineSt coordinates.add(outer.coordinates()); // If inner rings are set to null, return early. if (inner == null) { - return new AutoValue_Polygon(TYPE, null, coordinates); + return new Polygon(TYPE, null, coordinates); } for (LineString lineString : inner) { isLinearRing(lineString); coordinates.add(lineString.coordinates()); } - return new AutoValue_Polygon(TYPE, null, coordinates); + return new Polygon(TYPE, null, coordinates); } /** @@ -184,13 +192,13 @@ public static Polygon fromOuterInner(@NonNull LineString outer, @Nullable Boundi coordinates.add(outer.coordinates()); // If inner rings are set to null, return early. if (inner == null) { - return new AutoValue_Polygon(TYPE, bbox, coordinates); + return new Polygon(TYPE, bbox, coordinates); } for (LineString lineString : inner) { isLinearRing(lineString); coordinates.add(lineString.coordinates()); } - return new AutoValue_Polygon(TYPE, bbox, coordinates); + return new Polygon(TYPE, bbox, coordinates); } /** @@ -215,13 +223,13 @@ public static Polygon fromOuterInner(@NonNull LineString outer, coordinates.add(outer.coordinates()); // If inner rings are set to null, return early. if (inner == null || inner.isEmpty()) { - return new AutoValue_Polygon(TYPE, null, coordinates); + return new Polygon(TYPE, null, coordinates); } for (LineString lineString : inner) { isLinearRing(lineString); coordinates.add(lineString.coordinates()); } - return new AutoValue_Polygon(TYPE, null, coordinates); + return new Polygon(TYPE, null, coordinates); } /** @@ -247,13 +255,25 @@ public static Polygon fromOuterInner(@NonNull LineString outer, @Nullable Boundi coordinates.add(outer.coordinates()); // If inner rings are set to null, return early. if (inner == null) { - return new AutoValue_Polygon(TYPE, bbox, coordinates); + return new Polygon(TYPE, bbox, coordinates); } for (LineString lineString : inner) { isLinearRing(lineString); coordinates.add(lineString.coordinates()); } - return new AutoValue_Polygon(TYPE, bbox, coordinates); + return new Polygon(TYPE, bbox, coordinates); + } + + Polygon(String type, @Nullable BoundingBox bbox, List> coordinates) { + if (type == null) { + throw new NullPointerException("Null type"); + } + this.type = type; + this.bbox = bbox; + if (coordinates == null) { + throw new NullPointerException("Null coordinates"); + } + this.coordinates = coordinates; } /** @@ -299,7 +319,9 @@ public List inner() { */ @NonNull @Override - public abstract String type(); + public String type() { + return type; + } /** * A Feature Collection might have a member named {@code bbox} to include information on the @@ -313,7 +335,9 @@ public List inner() { */ @Nullable @Override - public abstract BoundingBox bbox(); + public BoundingBox bbox() { + return bbox; + } /** * Provides the list of {@link Point}s that make up the Polygon geometry. The first list holds the @@ -325,7 +349,9 @@ public List inner() { */ @NonNull @Override - public abstract List> coordinates(); + public List> coordinates() { + return coordinates; + } /** * This takes the currently defined values found inside this instance and converts it to a GeoJson @@ -350,7 +376,7 @@ public String toJson() { * @since 3.0.0 */ public static TypeAdapter typeAdapter(Gson gson) { - return new AutoValue_Polygon.GsonTypeAdapter(gson); + return new Polygon.GsonTypeAdapter(gson); } /** @@ -374,4 +400,139 @@ private static boolean isLinearRing(LineString lineString) { } return true; } + + @Override + public String toString() { + return "Polygon{" + + "type=" + type + ", " + + "bbox=" + bbox + ", " + + "coordinates=" + coordinates + + "}"; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof Polygon) { + Polygon that = (Polygon) o; + return (this.type.equals(that.type())) + && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) + && (this.coordinates.equals(that.coordinates())); + } + return false; + } + + @Override + public int hashCode() { + int h$ = 1; + h$ *= 1000003; + h$ ^= type.hashCode(); + h$ *= 1000003; + h$ ^= (bbox == null) ? 0 : bbox.hashCode(); + h$ *= 1000003; + h$ ^= coordinates.hashCode(); + return h$; + } + + public static final class GsonTypeAdapter extends TypeAdapter { + private volatile TypeAdapter string_adapter; + private volatile TypeAdapter boundingBox_adapter; + private volatile TypeAdapter>> list__list__point_adapter; + private final Gson gson; + public GsonTypeAdapter(Gson gson) { + this.gson = gson; + } + @Override + @SuppressWarnings("unchecked") + public void write(JsonWriter jsonWriter, Polygon object) throws IOException { + if (object == null) { + jsonWriter.nullValue(); + return; + } + jsonWriter.beginObject(); + jsonWriter.name("type"); + if (object.type() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + string_adapter.write(jsonWriter, object.type()); + } + jsonWriter.name("bbox"); + if (object.bbox() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + boundingBox_adapter.write(jsonWriter, object.bbox()); + } + jsonWriter.name("coordinates"); + if (object.coordinates() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter>> list__list__point_adapter = this.list__list__point_adapter; + if (list__list__point_adapter == null) { + this.list__list__point_adapter = list__list__point_adapter = (TypeAdapter>>) gson.getAdapter(TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, Point.class).getType())); + } + list__list__point_adapter.write(jsonWriter, object.coordinates()); + } + jsonWriter.endObject(); + } + @Override + @SuppressWarnings("unchecked") + public Polygon read(JsonReader jsonReader) throws IOException { + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + return null; + } + jsonReader.beginObject(); + String type = null; + BoundingBox bbox = null; + List> coordinates = null; + while (jsonReader.hasNext()) { + String _name = jsonReader.nextName(); + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + continue; + } + switch (_name) { + case "type": { + TypeAdapter string_adapter = this.string_adapter; + if (string_adapter == null) { + this.string_adapter = string_adapter = gson.getAdapter(String.class); + } + type = string_adapter.read(jsonReader); + break; + } + case "bbox": { + TypeAdapter boundingBox_adapter = this.boundingBox_adapter; + if (boundingBox_adapter == null) { + this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + } + bbox = boundingBox_adapter.read(jsonReader); + break; + } + case "coordinates": { + TypeAdapter>> list__list__point_adapter = this.list__list__point_adapter; + if (list__list__point_adapter == null) { + this.list__list__point_adapter = list__list__point_adapter = (TypeAdapter>>) gson.getAdapter(TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, Point.class).getType())); + } + coordinates = list__list__point_adapter.read(jsonReader); + break; + } + default: { + jsonReader.skipValue(); + } + } + } + jsonReader.endObject(); + return new Polygon(type, bbox, coordinates); + } + } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/CoordinateTypeAdapter.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/CoordinateTypeAdapter.java index 6e1bc276a..91be6f720 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/gson/CoordinateTypeAdapter.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/CoordinateTypeAdapter.java @@ -2,6 +2,7 @@ import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import com.mapbox.geojson.shifter.CoordinateShifterManager; import com.mapbox.geojson.utils.GeoJsonUtils; @@ -19,6 +20,11 @@ public class CoordinateTypeAdapter extends TypeAdapter> { @Override public void write(JsonWriter out, List value) throws IOException { + if (value == null) { + out.nullValue(); + return; + } + out.beginArray(); // Unshift coordinates @@ -37,6 +43,13 @@ public void write(JsonWriter out, List value) throws IOException { @Override public List read(JsonReader in) throws IOException { + + if (in.peek() == JsonToken.NULL) { + //in.nextNull(); + //return null; + throw new NullPointerException(); + } + List coordinates = new ArrayList(); in.beginArray(); while (in.hasNext()) { diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeoJsonAdapterFactory.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeoJsonAdapterFactory.java index c76868ca7..39f34ffb5 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeoJsonAdapterFactory.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeoJsonAdapterFactory.java @@ -1,6 +1,21 @@ package com.mapbox.geojson.gson; +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.typeadapters.RuntimeTypeAdapterFactory; +import com.mapbox.geojson.BoundingBox; +import com.mapbox.geojson.Feature; +import com.mapbox.geojson.FeatureCollection; +import com.mapbox.geojson.Geometry; +import com.mapbox.geojson.GeometryCollection; +import com.mapbox.geojson.LineString; +import com.mapbox.geojson.MultiLineString; +import com.mapbox.geojson.MultiPoint; +import com.mapbox.geojson.MultiPolygon; +import com.mapbox.geojson.Point; +import com.mapbox.geojson.Polygon; import com.ryanharter.auto.value.gson.GsonTypeAdapterFactory; /** @@ -20,6 +35,36 @@ public abstract class GeoJsonAdapterFactory implements TypeAdapterFactory { * @since 3.0.0 */ public static TypeAdapterFactory create() { - return new AutoValueGson_GeoJsonAdapterFactory(); + return new GeoJsonAdapterFactoryIml(); + } + + public static final class GeoJsonAdapterFactoryIml extends GeoJsonAdapterFactory { + @Override + @SuppressWarnings("unchecked") + public TypeAdapter create(Gson gson, TypeToken type) { + Class rawType = type.getRawType(); + /*if (BoundingBox.class.isAssignableFrom(rawType)) { + return (TypeAdapter) BoundingBox.typeAdapter(gson); + } else */ + if (Feature.class.isAssignableFrom(rawType)) { + return (TypeAdapter) Feature.typeAdapter(gson); + } else if (FeatureCollection.class.isAssignableFrom(rawType)) { + return (TypeAdapter) FeatureCollection.typeAdapter(gson); + } else if (GeometryCollection.class.isAssignableFrom(rawType)) { + return (TypeAdapter) GeometryCollection.typeAdapter(gson); + } else if (LineString.class.isAssignableFrom(rawType)) { + return (TypeAdapter) LineString.typeAdapter(gson); + } else if (MultiLineString.class.isAssignableFrom(rawType)) { + return (TypeAdapter) MultiLineString.typeAdapter(gson); + } else if (MultiPoint.class.isAssignableFrom(rawType)) { + return (TypeAdapter) MultiPoint.typeAdapter(gson); + } else if (MultiPolygon.class.isAssignableFrom(rawType)) { + return (TypeAdapter) MultiPolygon.typeAdapter(gson); + } else if (Polygon.class.isAssignableFrom(rawType)) { + return (TypeAdapter) Polygon.typeAdapter(gson); + } + return null; + } } } + diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryDeserializer.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryDeserializer.java index d5ad6bee7..f376d3c72 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryDeserializer.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryDeserializer.java @@ -51,7 +51,7 @@ public Geometry deserialize(JsonElement json, Type typeOfT, JsonDeserializationC try { // Use the current context to deserialize it - Type classType = Class.forName("com.mapbox.geojson.AutoValue_" + geometryType); + Type classType = Class.forName("com.mapbox.geojson." + geometryType); return context.deserialize(json, classType); } catch (ClassNotFoundException classNotFoundException) { // Unknown geometry diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryGeoJson.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryGeoJson.java index 8705ec945..356435c32 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryGeoJson.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryGeoJson.java @@ -3,9 +3,16 @@ import android.support.annotation.NonNull; import com.google.gson.GsonBuilder; +import com.google.gson.typeadapters.RuntimeTypeAdapterFactory; import com.mapbox.geojson.BoundingBox; import com.mapbox.geojson.Geometry; +import com.mapbox.geojson.GeometryCollection; +import com.mapbox.geojson.LineString; +import com.mapbox.geojson.MultiLineString; +import com.mapbox.geojson.MultiPoint; +import com.mapbox.geojson.MultiPolygon; import com.mapbox.geojson.Point; +import com.mapbox.geojson.Polygon; /** * This is a utility class that helps create a Geometry instance from a JSON string. @@ -22,11 +29,26 @@ public class GeometryGeoJson { * @since 4.0.0 */ public static Geometry fromJson(@NonNull String json) { + +// final RuntimeTypeAdapterFactory geometryFactory = RuntimeTypeAdapterFactory +// .of(Geometry.class, "type") +// .registerSubtype(GeometryCollection.class, "GeometryCollection") +// .registerSubtype(Point.class, "Point") +// .registerSubtype(MultiPoint.class, "MultiPoint") +// .registerSubtype(LineString.class, "LineString") +// .registerSubtype(MultiLineString.class, "MultiLineString") +// .registerSubtype(Polygon.class, "Polygon") +// .registerSubtype(MultiPolygon.class, "MultiPolygon") +// ; + GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); + gson.registerTypeAdapter(Point.class, new PointDeserializer()); gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); + + gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); gson.registerTypeAdapter(Geometry.class, new GeometryDeserializer()); + return gson.create().fromJson(json, Geometry.class); } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryTypeAdapter.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryTypeAdapter.java index c3ae2704e..39ff475c1 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryTypeAdapter.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryTypeAdapter.java @@ -2,11 +2,16 @@ import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; +import com.google.gson.stream.MalformedJsonException; import com.mapbox.geojson.CoordinateContainer; import com.mapbox.geojson.Geometry; +import com.mapbox.geojson.shifter.CoordinateShifterManager; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; /** * Converts {@code Geometry} instances to JSON and JSON to @@ -25,13 +30,15 @@ public void write(JsonWriter out, Geometry value) throws IOException { out.name("bbox").jsonValue(value.bbox().toJson()); } if (value instanceof CoordinateContainer) { - out.name("coordinates").jsonValue(((CoordinateContainer) value).coordinates().toString()); + + String coordinates = ((CoordinateContainer) value).coordinates().toString(); + out.name("coordinates").jsonValue(coordinates); } out.endObject(); } @Override public Geometry read(JsonReader in) throws IOException { - return null; + return null; } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/PointDeserializer.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/PointDeserializer.java index bb2cbfc62..ab2be37d6 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/gson/PointDeserializer.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/PointDeserializer.java @@ -4,9 +4,12 @@ import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.mapbox.geojson.BoundingBox; import com.mapbox.geojson.Point; import java.lang.reflect.Type; +import java.util.List; /** * Deserialize the coordinates inside the json into {@link Point}s capturing the same information. @@ -27,9 +30,8 @@ public PointDeserializer() { } /** - * Deserialize the coordinates inside the json into {@link Point}s capturing the same information. - * Otherwise when deserializing, you'll most likely see this error: Required to handle the - * "Expected BEGIN_OBJECT but was BEGIN_ARRAY". + * Deserialize Point object or coordinates + * inside the json into {@link Point}s capturing the same information. * * @param json a class representing an element of Json * @param typeOfT common superinterface for all types in the Java @@ -41,7 +43,28 @@ public PointDeserializer() { */ @Override public Point deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { - JsonArray rawCoordinates = json.getAsJsonArray(); + + JsonElement jsonElement = json; + BoundingBox boundingBox = null; + + if (json.isJsonObject()) { + JsonObject jsonObject = json.getAsJsonObject(); + jsonElement = jsonObject.get("type"); + if (jsonElement.isJsonNull()) { + throw new NullPointerException(); + } + + jsonElement = jsonObject.get("bbox"); + if (jsonElement != null && !jsonElement.isJsonNull()) { + boundingBox = context.deserialize(jsonElement, BoundingBox.class); + } + jsonElement = jsonObject.get("coordinates"); + if (jsonElement.isJsonNull()) { + throw new NullPointerException(); + } + } + + JsonArray rawCoordinates = jsonElement.getAsJsonArray(); double longitude = rawCoordinates.get(0).getAsDouble(); double latitude = rawCoordinates.get(1).getAsDouble(); @@ -49,10 +72,10 @@ public Point deserialize(JsonElement json, Type typeOfT, JsonDeserializationCont // Includes altitude if (rawCoordinates.size() > 2) { double altitude = rawCoordinates.get(2).getAsDouble(); - return Point.fromLngLat(longitude, latitude, altitude); + return Point.fromLngLat(longitude, latitude, altitude, boundingBox); } // It doesn't have altitude - return Point.fromLngLat(longitude, latitude); + return Point.fromLngLat(longitude, latitude, boundingBox); } } diff --git a/services-geojson/src/test/java/com/mapbox/geojson/FeatureTest.java b/services-geojson/src/test/java/com/mapbox/geojson/FeatureTest.java index 1af04568a..4d7eb655d 100644 --- a/services-geojson/src/test/java/com/mapbox/geojson/FeatureTest.java +++ b/services-geojson/src/test/java/com/mapbox/geojson/FeatureTest.java @@ -18,7 +18,6 @@ public class FeatureTest extends TestUtils { - private static final String SAMPLE_FEATURE = "sample-feature.json"; private static final String SAMPLE_FEATURE_POINT = "sample-feature-point-all.json"; @Test @@ -48,7 +47,9 @@ public void bbox_doesNotSerializeWhenNotPresent() throws Exception { points.add(Point.fromLngLat(2.0, 3.0)); LineString lineString = LineString.fromLngLats(points); Feature feature = Feature.fromGeometry(lineString); - compareJson(feature.toJson(), + + String featureJsonString = feature.toJson(); + compareJson(featureJsonString, "{\"type\":\"Feature\",\"geometry\":{\"type\":" + "\"LineString\",\"coordinates\":[[1,2],[2,3]]}}"); } @@ -85,7 +86,7 @@ public void bbox_doesSerializeWhenPresent() throws Exception { } @Test - public void test_point_feature_fromJson() throws IOException { + public void point_feature_fromJson() throws IOException { final String json = "{ \"type\": \"Feature\"," + "\"geometry\": { \"type\": \"Point\", \"coordinates\": [ 125.6, 10.1] }," + "\"properties\": {\"name\": \"Dinagat Islands\" }}"; @@ -98,7 +99,7 @@ public void test_point_feature_fromJson() throws IOException { } @Test - public void test_linestring_feature_fromJson() throws IOException { + public void linestring_feature_fromJson() throws IOException { final String json = "{ \"type\": \"Feature\"," + "\"geometry\": { \"type\": \"LineString\", "+ " \"coordinates\": [[ 102.0, 20],[103.0, 3.0],[104.0, 4.0], [105.0, 5.0]]}," + @@ -116,7 +117,7 @@ public void test_linestring_feature_fromJson() throws IOException { } @Test - public void test_point_feature_toJson() throws IOException { + public void point_feature_toJson() throws IOException { JsonObject properties = new JsonObject(); properties.addProperty("name", "Dinagat Islands"); Feature geo = Feature.fromGeometry(Point.fromLngLat(125.6, 10.1), @@ -130,6 +131,27 @@ public void test_point_feature_toJson() throws IOException { compareJson(expectedJson, geoJsonString); } + @Test + public void linestring_feature_toJson() throws IOException { + JsonObject properties = new JsonObject(); + properties.addProperty("name", "Dinagat Islands"); + + List points = new ArrayList<>(); + points.add(Point.fromLngLat(1.0, 1.0)); + points.add(Point.fromLngLat(2.0, 2.0)); + points.add(Point.fromLngLat(3.0, 3.0)); + LineString lineString = LineString.fromLngLats(points); + + Feature geo = Feature.fromGeometry(lineString, properties); + String geoJsonString = geo.toJson(); + + String expectedJson = "{ \"type\": \"Feature\"," + + "\"geometry\": { \"type\": \"LineString\", \"coordinates\": [[1,1],[2,2],[3,3]]}," + + "\"properties\": {\"name\": \"Dinagat Islands\" }}"; + + compareJson(expectedJson, geoJsonString); + } + @Test public void testNullProperties() { List coordinates = new ArrayList<>(); @@ -163,19 +185,34 @@ public void testNonNullProperties() { @Test public void testNullPropertiesJson() { - String jsonString = "{\"type\":\"Feature\",\"bbox\":[1.0,2.0,3.0,4.0],\"geometry\":" + final String jsonString = + "{\"type\":\"Feature\"," + + " \"bbox\":[1.0,2.0,3.0,4.0]," + + " \"geometry\":" + "{\"type\":\"LineString\",\"coordinates\":[[1.0,2.0],[2.0,3.0]]}}"; + Feature feature = Feature.fromJson(jsonString); // Json( null Properties) -> Feature (empty Properties) -> Json(null Properties) String fromFeatureJsonString = feature.toJson(); - assertEquals(fromFeatureJsonString, jsonString); + compareJson(fromFeatureJsonString, jsonString); } @Test - public void test_fromJson_toJson() throws IOException { - final String jsonString = loadJsonFixture(SAMPLE_FEATURE_POINT); + public void pointFeature_fromJson_toJson() throws IOException { + final String jsonString = + "{\"id\" : \"id0\"," + + " \"bbox\": [-120.0, -60.0, 120.0, 60.0]," + + " \"geometry\": {" + + " \"bbox\": [-110.0, -50.0, 110.0, 50.0]," + + " \"coordinates\": [ 100.0, 0.0], " + + " \"type\": \"Point\"}," + + "\"type\": \"Feature\"," + + "\"properties\": {\"prop0\": \"value0\", \"prop1\": \"value1\"}" + + "}"; + + Feature featureFromJson = Feature.fromJson(jsonString); String jsonStringFromFeature = featureFromJson.toJson(); diff --git a/services-geojson/src/test/java/com/mapbox/geojson/GeometryCollectionTest.java b/services-geojson/src/test/java/com/mapbox/geojson/GeometryCollectionTest.java index 42955c5be..2f447a9e5 100644 --- a/services-geojson/src/test/java/com/mapbox/geojson/GeometryCollectionTest.java +++ b/services-geojson/src/test/java/com/mapbox/geojson/GeometryCollectionTest.java @@ -10,6 +10,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class GeometryCollectionTest extends TestUtils { @@ -133,8 +134,22 @@ public void fromJson() throws IOException { @Test public void toJson() throws IOException { - final String json = loadJsonFixture(SAMPLE_GEOMETRYCOLLECTION); - GeometryCollection geo = GeometryCollection.fromJson(json); - compareJson(json, geo.toJson()); + final String jsonOriginal = loadJsonFixture(SAMPLE_GEOMETRYCOLLECTION); + + List geometries = new ArrayList<>(2); + geometries.add(Point.fromLngLat(100, 0, + BoundingBox.fromLngLats(-110, -30,110, 30))); + geometries.add(LineString.fromLngLats( + Arrays.asList(Point.fromLngLat(101, 0), + Point.fromLngLat(102, 1)), + BoundingBox.fromLngLats(-110, -30,110, 30))); + + GeometryCollection geometryCollection = + GeometryCollection.fromGeometries(geometries, + BoundingBox.fromLngLats(-120, -40,120, 40)); + + String jsonString = geometryCollection.toJson(); + compareJson(jsonOriginal, jsonString); + } } diff --git a/services-geojson/src/test/java/com/mapbox/geojson/GeometryTest.java b/services-geojson/src/test/java/com/mapbox/geojson/GeometryTest.java index f4e8bfc12..b467d0713 100644 --- a/services-geojson/src/test/java/com/mapbox/geojson/GeometryTest.java +++ b/services-geojson/src/test/java/com/mapbox/geojson/GeometryTest.java @@ -6,8 +6,10 @@ import org.junit.Test; import java.io.IOException; +import java.util.Arrays; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; public class GeometryTest extends TestUtils { @@ -17,6 +19,67 @@ public class GeometryTest extends TestUtils { public void fromJson() throws IOException { final String json = loadJsonFixture(SAMPLE_GEOMETRY_COLLECTION); Geometry geo = GeometryGeoJson.fromJson(json); - assertEquals(geo.type(), "GeometryCollection"); + //assertEquals(geo.type(), "GeometryCollection"); + int i = 0; + } + + @Test + public void pointFromJson() throws IOException { + Geometry geometry = GeometryGeoJson.fromJson("{\"coordinates\": [2,3]," + + "\"type\":\"Point\",\"bbox\":[1.0,2.0,3.0,4.0]}"); + + assertNotNull(geometry); + assertNotNull(geometry.bbox()); + assertEquals(1.0, geometry.bbox().southwest().longitude(), DELTA); + assertEquals(2.0, geometry.bbox().southwest().latitude(), DELTA); + assertEquals(3.0, geometry.bbox().northeast().longitude(), DELTA); + assertEquals(4.0, geometry.bbox().northeast().latitude(), DELTA); + assertNotNull(((Point)geometry).coordinates()); + assertEquals(2, ((Point)geometry).longitude(), DELTA); + assertEquals(3, ((Point)geometry).latitude(), DELTA); + } + + @Test + public void pointToJson() throws IOException { + Geometry geometry = Point.fromLngLat(2, 3, + BoundingBox.fromLngLats(1, 2, 3, 4)); + String pointStr = geometry.toJson(); + compareJson("{\"coordinates\": [2,3]," + + "\"type\":\"Point\",\"bbox\":[1.0,2.0,3.0,4.0]}", + pointStr); + } + + @Test + public void lineStringFromJson() throws Exception { + Geometry lineString = GeometryGeoJson.fromJson("{\"coordinates\":[[1,2],[2,3],[3,4]]," + + "\"type\":\"LineString\",\"bbox\":[1.0,2.0,3.0,4.0]}"); + + assertNotNull(lineString); + assertNotNull(lineString.bbox()); + assertEquals(1.0, lineString.bbox().southwest().longitude(), DELTA); + assertEquals(2.0, lineString.bbox().southwest().latitude(), DELTA); + assertEquals(3.0, lineString.bbox().northeast().longitude(), DELTA); + assertEquals(4.0, lineString.bbox().northeast().latitude(), DELTA); + assertNotNull(((LineString)lineString).coordinates()); + assertEquals(1, ((LineString)lineString).coordinates().get(0).longitude(), DELTA); + assertEquals(2, ((LineString)lineString).coordinates().get(0).latitude(), DELTA); + assertEquals(2, ((LineString)lineString).coordinates().get(1).longitude(), DELTA); + assertEquals(3, ((LineString)lineString).coordinates().get(1).latitude(), DELTA); + assertEquals(3, ((LineString)lineString).coordinates().get(2).longitude(), DELTA); + assertEquals(4, ((LineString)lineString).coordinates().get(2).latitude(), DELTA); + } + + @Test + public void lineStringToJson() throws Exception { + + Geometry geometry = LineString.fromLngLats( + Arrays.asList(Point.fromLngLat(1, 2), + Point.fromLngLat(2, 3), + Point.fromLngLat(3, 4)), + BoundingBox.fromLngLats(1, 2, 3, 4)); + String geometryJsonStr = geometry.toJson(); + String expectedJsonString = "{\"coordinates\":[[1,2],[2,3],[3,4]]," + + "\"type\":\"LineString\",\"bbox\":[1.0,2.0,3.0,4.0]}"; + compareJson(expectedJsonString, geometryJsonStr); } } diff --git a/services-geojson/src/test/java/com/mapbox/geojson/LineStringTest.java b/services-geojson/src/test/java/com/mapbox/geojson/LineStringTest.java index bd86428de..111426c53 100644 --- a/services-geojson/src/test/java/com/mapbox/geojson/LineStringTest.java +++ b/services-geojson/src/test/java/com/mapbox/geojson/LineStringTest.java @@ -93,6 +93,26 @@ public void bbox_doesSerializeWhenPresent() throws Exception { lineStringJson); } + @Test + public void bbox_doesDeserializeWhenPresent() throws Exception { + LineString lineString = LineString.fromJson("{\"coordinates\":[[1,2],[2,3],[3,4]]," + + "\"type\":\"LineString\",\"bbox\":[1.0,2.0,3.0,4.0]}"); + + assertNotNull(lineString); + assertNotNull(lineString.bbox()); + assertEquals(1.0, lineString.bbox().southwest().longitude(), DELTA); + assertEquals(2.0, lineString.bbox().southwest().latitude(), DELTA); + assertEquals(3.0, lineString.bbox().northeast().longitude(), DELTA); + assertEquals(4.0, lineString.bbox().northeast().latitude(), DELTA); + assertNotNull(lineString.coordinates()); + assertEquals(1, lineString.coordinates().get(0).longitude(), DELTA); + assertEquals(2, lineString.coordinates().get(0).latitude(), DELTA); + assertEquals(2, lineString.coordinates().get(1).longitude(), DELTA); + assertEquals(3, lineString.coordinates().get(1).latitude(), DELTA); + assertEquals(3, lineString.coordinates().get(2).longitude(), DELTA); + assertEquals(4, lineString.coordinates().get(2).latitude(), DELTA); + } + @Test public void testSerializable() throws Exception { List points = new ArrayList<>(); @@ -119,7 +139,8 @@ public void fromJson() throws IOException { public void toJson() throws IOException { final String json = loadJsonFixture(SAMPLE_LINESTRING_FIXTURE); LineString geo = LineString.fromJson(json); - compareJson(json, geo.toJson()); + String geoJsonString = geo.toJson(); + compareJson(geoJsonString, json); } @Test diff --git a/services-geojson/src/test/java/com/mapbox/geojson/PointTest.java b/services-geojson/src/test/java/com/mapbox/geojson/PointTest.java index 12aff4315..f6745693a 100644 --- a/services-geojson/src/test/java/com/mapbox/geojson/PointTest.java +++ b/services-geojson/src/test/java/com/mapbox/geojson/PointTest.java @@ -13,7 +13,9 @@ import org.junit.rules.ExpectedException; import java.io.IOException; +import java.lang.reflect.Array; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class PointTest extends TestUtils { @@ -97,15 +99,27 @@ public void bbox_returnsCorrectBbox() throws Exception { @Test public void bbox_doesSerializeWhenPresent() throws Exception { - List points = new ArrayList<>(); - points.add(Point.fromLngLat(1.0, 1.0)); - points.add(Point.fromLngLat(2.0, 2.0)); - points.add(Point.fromLngLat(3.0, 3.0)); BoundingBox bbox = BoundingBox.fromLngLats(1.0, 2.0, 3.0, 4.0); - LineString lineString = LineString.fromLngLats(points, bbox); - compareJson(lineString.toJson(), - "{\"coordinates\":[[1,1],[2,2],[3,3]]," - + "\"type\":\"LineString\",\"bbox\":[1.0,2.0,3.0,4.0]}"); + Point point = Point.fromLngLat(2.0, 2.0, bbox); + compareJson(point.toJson(), + "{\"coordinates\": [2,2]," + + "\"type\":\"Point\",\"bbox\":[1.0,2.0,3.0,4.0]}"); + } + + @Test + public void bbox_doesDeserializeWhenPresent() throws Exception { + Point point = Point.fromJson("{\"coordinates\": [2,3]," + + "\"type\":\"Point\",\"bbox\":[1.0,2.0,3.0,4.0]}"); + + assertNotNull(point); + assertNotNull(point.bbox()); + assertEquals(1.0, point.bbox().southwest().longitude(), DELTA); + assertEquals(2.0, point.bbox().southwest().latitude(), DELTA); + assertEquals(3.0, point.bbox().northeast().longitude(), DELTA); + assertEquals(4.0, point.bbox().northeast().latitude(), DELTA); + assertNotNull(point.coordinates()); + assertEquals(2, point.longitude(), DELTA); + assertEquals(3, point.latitude(), DELTA); } @Test @@ -122,7 +136,8 @@ public void testSerializable() throws Exception { @Test public void fromJson() throws IOException { - final String json = loadJsonFixture(SAMPLE_POINT); + final String json = + "{ \"type\": \"Point\", \"coordinates\": [ 100, 0] }"; Point geo = Point.fromJson(json); assertEquals(geo.type(), "Point"); assertEquals(geo.longitude(), 100.0, DELTA); @@ -136,7 +151,8 @@ public void fromJson() throws IOException { @Test public void toJson() throws IOException { - final String json = loadJsonFixture(SAMPLE_POINT); + final String json = + "{ \"type\": \"Point\", \"coordinates\": [ 100, 0] }"; Point geo = Point.fromJson(json); compareJson(json, geo.toJson()); } diff --git a/services-geojson/src/test/java/com/mapbox/geojson/gson/PointDeserializerTest.java b/services-geojson/src/test/java/com/mapbox/geojson/gson/PointDeserializerTest.java index e1d3d92d8..6a5f38cb9 100644 --- a/services-geojson/src/test/java/com/mapbox/geojson/gson/PointDeserializerTest.java +++ b/services-geojson/src/test/java/com/mapbox/geojson/gson/PointDeserializerTest.java @@ -34,7 +34,7 @@ public void deserialize_sanity() throws Exception { @Test public void point_doesNotDeserializeObject() throws Exception { - thrown.expect(JsonSyntaxException.class); + thrown.expect(NullPointerException.class); String jsonString = "{ \"coordinates\": [100.0, 0.0, 200.0]}"; GsonBuilder gsonBuilder = new GsonBuilder() From c293b78eff3ccc4d1b75a8e4649fde16a29d2276 Mon Sep 17 00:00:00 2001 From: osana Date: Tue, 29 Jan 2019 16:38:48 -0500 Subject: [PATCH 2/2] removing dependency on PointDeserializer, PointSerializer, BoundingBoxDeserializer and BoundingBoxSerializer, GeometryDeserializer in favor of TypeAdapters --- .../v5/models/DirectionsJsonObject.java | 4 +- .../v5/models/DirectionsResponse.java | 4 +- .../directions/v5/models/DirectionsRoute.java | 4 +- .../directions/v5/models/RouteOptions.java | 4 +- .../api/geocoding/v5/MapboxGeocoding.java | 12 +- .../geocoding/v5/models/CarmenFeature.java | 18 +- .../v5/models/GeocodingResponse.java | 18 +- .../v5/models/CarmenFeatureTest.java | 2 +- .../RuntimeTypeAdapterFactory.java | 289 ++++++++++++++++++ .../gson/typeadapters/package-info.java | 5 + .../geojson/BaseCoordinatesTypeAdapter.java | 83 +++++ .../geojson/BaseGeometryTypeAdapter.java | 134 ++++++++ .../java/com/mapbox/geojson/BoundingBox.java | 32 +- .../mapbox/geojson/CoordinateContainer.java | 1 + .../main/java/com/mapbox/geojson/Feature.java | 208 +++++++------ .../com/mapbox/geojson/FeatureCollection.java | 158 +++++----- .../geojson/GeometryAdapterFactory.java | 37 +++ .../mapbox/geojson/GeometryCollection.java | 175 +++++------ .../java/com/mapbox/geojson/LineString.java | 144 ++------- .../ListOfDoublesCoordinatesTypeAdapter.java | 25 ++ ...stOfListOfPointCoordinatesTypeAdapter.java | 74 +++++ .../ListOfPointCoordinatesTypeAdapter.java | 57 ++++ ...stofListOfPointCoordinatesTypeAdapter.java | 86 ++++++ .../com/mapbox/geojson/MultiLineString.java | 147 +++------ .../java/com/mapbox/geojson/MultiPoint.java | 150 +++------ .../java/com/mapbox/geojson/MultiPolygon.java | 146 ++------- .../main/java/com/mapbox/geojson/Point.java | 167 +++------- .../PointAsCoordinatesTypeAdapter.java | 25 ++ .../main/java/com/mapbox/geojson/Polygon.java | 149 +++------ .../geojson/gson/BoundingBoxDeserializer.java | 3 + .../geojson/gson/BoundingBoxSerializer.java | 3 + .../geojson/gson/BoundingBoxTypeAdapter.java | 90 ++++++ .../geojson/gson/CoordinateTypeAdapter.java | 16 +- .../geojson/gson/GeoJsonAdapterFactory.java | 20 +- .../geojson/gson/GeometryDeserializer.java | 3 + .../mapbox/geojson/gson/GeometryGeoJson.java | 27 +- .../geojson/gson/GeometryTypeAdapter.java | 14 +- .../geojson/gson/PointDeserializer.java | 38 +-- .../mapbox/geojson/gson/PointSerializer.java | 3 + .../java/com/mapbox/geojson/GeoJsonTest.java | 26 +- .../geojson/GeometryCollectionTest.java | 22 +- .../java/com/mapbox/geojson/GeometryTest.java | 14 +- .../com/mapbox/geojson/LineStringTest.java | 6 +- .../mapbox/geojson/MultiLineStringTest.java | 7 +- .../com/mapbox/geojson/MultiPointTest.java | 6 +- .../com/mapbox/geojson/MultiPolygonTest.java | 11 +- .../java/com/mapbox/geojson/PolygonTest.java | 14 +- .../geojson/gson/PointDeserializerTest.java | 2 +- .../mapbox/api/tilequery/MapboxTilequery.java | 11 +- 49 files changed, 1563 insertions(+), 1131 deletions(-) create mode 100644 services-geojson/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java create mode 100644 services-geojson/src/main/java/com/google/gson/typeadapters/package-info.java create mode 100644 services-geojson/src/main/java/com/mapbox/geojson/BaseCoordinatesTypeAdapter.java create mode 100644 services-geojson/src/main/java/com/mapbox/geojson/BaseGeometryTypeAdapter.java create mode 100644 services-geojson/src/main/java/com/mapbox/geojson/GeometryAdapterFactory.java create mode 100644 services-geojson/src/main/java/com/mapbox/geojson/ListOfDoublesCoordinatesTypeAdapter.java create mode 100644 services-geojson/src/main/java/com/mapbox/geojson/ListOfListOfPointCoordinatesTypeAdapter.java create mode 100644 services-geojson/src/main/java/com/mapbox/geojson/ListOfPointCoordinatesTypeAdapter.java create mode 100644 services-geojson/src/main/java/com/mapbox/geojson/ListofListofListOfPointCoordinatesTypeAdapter.java create mode 100644 services-geojson/src/main/java/com/mapbox/geojson/PointAsCoordinatesTypeAdapter.java create mode 100644 services-geojson/src/main/java/com/mapbox/geojson/gson/BoundingBoxTypeAdapter.java diff --git a/services-directions/src/main/java/com/mapbox/api/directions/v5/models/DirectionsJsonObject.java b/services-directions/src/main/java/com/mapbox/api/directions/v5/models/DirectionsJsonObject.java index 3d3555cbe..cf5c8a599 100644 --- a/services-directions/src/main/java/com/mapbox/api/directions/v5/models/DirectionsJsonObject.java +++ b/services-directions/src/main/java/com/mapbox/api/directions/v5/models/DirectionsJsonObject.java @@ -3,7 +3,7 @@ import com.google.gson.GsonBuilder; import com.mapbox.api.directions.v5.DirectionsAdapterFactory; import com.mapbox.geojson.Point; -import com.mapbox.geojson.gson.PointSerializer; +import com.mapbox.geojson.PointAsCoordinatesTypeAdapter; import java.io.Serializable; @@ -24,7 +24,7 @@ public class DirectionsJsonObject implements Serializable { public String toJson() { GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapterFactory(DirectionsAdapterFactory.create()); - gson.registerTypeAdapter(Point.class, new PointSerializer()); + gson.registerTypeAdapter(Point.class, new PointAsCoordinatesTypeAdapter()); return gson.create().toJson(this); } } diff --git a/services-directions/src/main/java/com/mapbox/api/directions/v5/models/DirectionsResponse.java b/services-directions/src/main/java/com/mapbox/api/directions/v5/models/DirectionsResponse.java index f7b9f18ce..522a189b3 100644 --- a/services-directions/src/main/java/com/mapbox/api/directions/v5/models/DirectionsResponse.java +++ b/services-directions/src/main/java/com/mapbox/api/directions/v5/models/DirectionsResponse.java @@ -9,7 +9,7 @@ import com.google.gson.TypeAdapter; import com.mapbox.api.directions.v5.DirectionsAdapterFactory; import com.mapbox.geojson.Point; -import com.mapbox.geojson.gson.PointDeserializer; +import com.mapbox.geojson.PointAsCoordinatesTypeAdapter; import java.util.List; @@ -129,7 +129,7 @@ public static TypeAdapter typeAdapter(Gson gson) { public static DirectionsResponse fromJson(String json) { GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapterFactory(DirectionsAdapterFactory.create()); - gson.registerTypeAdapter(Point.class, new PointDeserializer()); + gson.registerTypeAdapter(Point.class, new PointAsCoordinatesTypeAdapter()); return gson.create().fromJson(json, DirectionsResponse.class); } diff --git a/services-directions/src/main/java/com/mapbox/api/directions/v5/models/DirectionsRoute.java b/services-directions/src/main/java/com/mapbox/api/directions/v5/models/DirectionsRoute.java index 7ed1886bb..882ab4dfe 100644 --- a/services-directions/src/main/java/com/mapbox/api/directions/v5/models/DirectionsRoute.java +++ b/services-directions/src/main/java/com/mapbox/api/directions/v5/models/DirectionsRoute.java @@ -10,7 +10,7 @@ import com.mapbox.api.directions.v5.DirectionsAdapterFactory; import com.mapbox.api.directions.v5.MapboxDirections; import com.mapbox.geojson.Point; -import com.mapbox.geojson.gson.PointDeserializer; +import com.mapbox.geojson.PointAsCoordinatesTypeAdapter; import java.util.List; @@ -155,7 +155,7 @@ public static TypeAdapter typeAdapter(Gson gson) { public static DirectionsRoute fromJson(String json) { GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapterFactory(DirectionsAdapterFactory.create()); - gson.registerTypeAdapter(Point.class, new PointDeserializer()); + gson.registerTypeAdapter(Point.class, new PointAsCoordinatesTypeAdapter()); return gson.create().fromJson(json, DirectionsRoute.class); } diff --git a/services-directions/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java b/services-directions/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java index e8c0a32b5..5cc9360b5 100644 --- a/services-directions/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java +++ b/services-directions/src/main/java/com/mapbox/api/directions/v5/models/RouteOptions.java @@ -12,7 +12,7 @@ import com.mapbox.api.directions.v5.DirectionsCriteria; import com.mapbox.api.directions.v5.MapboxDirections; import com.mapbox.geojson.Point; -import com.mapbox.geojson.gson.PointDeserializer; +import com.mapbox.geojson.PointAsCoordinatesTypeAdapter; import java.util.List; @@ -334,7 +334,7 @@ public static TypeAdapter typeAdapter(Gson gson) { public static RouteOptions fromJson(String json) { GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapterFactory(DirectionsAdapterFactory.create()); - gson.registerTypeAdapter(Point.class, new PointDeserializer()); + gson.registerTypeAdapter(Point.class, new PointAsCoordinatesTypeAdapter()); return gson.create().fromJson(json, RouteOptions.class); } diff --git a/services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/MapboxGeocoding.java b/services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/MapboxGeocoding.java index 5671bca02..8fa06f1ef 100644 --- a/services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/MapboxGeocoding.java +++ b/services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/MapboxGeocoding.java @@ -17,11 +17,9 @@ import com.mapbox.core.utils.MapboxUtils; import com.mapbox.core.utils.TextUtils; import com.mapbox.geojson.BoundingBox; -import com.mapbox.geojson.Geometry; +import com.mapbox.geojson.GeometryAdapterFactory; import com.mapbox.geojson.Point; -import com.mapbox.geojson.gson.BoundingBoxDeserializer; -import com.mapbox.geojson.gson.GeometryDeserializer; -import com.mapbox.geojson.gson.PointDeserializer; +import com.mapbox.geojson.gson.BoundingBoxTypeAdapter; import java.io.IOException; import java.util.ArrayList; @@ -71,11 +69,11 @@ protected MapboxGeocoding() { @Override protected GsonBuilder getGsonBuilder() { + return new GsonBuilder() .registerTypeAdapterFactory(GeocodingAdapterFactory.create()) - .registerTypeAdapter(Point.class, new PointDeserializer()) - .registerTypeAdapter(Geometry.class, new GeometryDeserializer()) - .registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); + .registerTypeAdapterFactory(GeometryAdapterFactory.create()) + .registerTypeAdapter(BoundingBox.class, new BoundingBoxTypeAdapter()); } @Override diff --git a/services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/models/CarmenFeature.java b/services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/models/CarmenFeature.java index a2bf0da00..d9d453380 100644 --- a/services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/models/CarmenFeature.java +++ b/services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/models/CarmenFeature.java @@ -13,12 +13,9 @@ import com.mapbox.geojson.Feature; import com.mapbox.geojson.GeoJson; import com.mapbox.geojson.Geometry; +import com.mapbox.geojson.GeometryAdapterFactory; import com.mapbox.geojson.Point; -import com.mapbox.geojson.gson.BoundingBoxDeserializer; -import com.mapbox.geojson.gson.BoundingBoxSerializer; -import com.mapbox.geojson.gson.GeometryDeserializer; -import com.mapbox.geojson.gson.GeometryTypeAdapter; -import com.mapbox.geojson.gson.PointDeserializer; +import com.mapbox.geojson.gson.BoundingBoxTypeAdapter; import java.io.Serializable; import java.util.List; @@ -55,10 +52,10 @@ public abstract class CarmenFeature implements GeoJson, Serializable { */ @NonNull public static CarmenFeature fromJson(@NonNull String json) { + Gson gson = new GsonBuilder() - .registerTypeAdapter(Point.class, new PointDeserializer()) - .registerTypeAdapter(Geometry.class, new GeometryDeserializer()) - .registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()) + .registerTypeAdapterFactory(GeometryAdapterFactory.create()) + .registerTypeAdapter(BoundingBox.class, new BoundingBoxTypeAdapter()) .registerTypeAdapterFactory(GeocodingAdapterFactory.create()) .create(); CarmenFeature feature = gson.fromJson(json, CarmenFeature.class); @@ -296,9 +293,10 @@ public static TypeAdapter typeAdapter(Gson gson) { @Override @SuppressWarnings("unused") public String toJson() { + Gson gson = new GsonBuilder() - .registerTypeAdapter(Geometry.class, new GeometryTypeAdapter()) - .registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()) + .registerTypeAdapterFactory(GeometryAdapterFactory.create()) + .registerTypeAdapter(BoundingBox.class, new BoundingBoxTypeAdapter()) .registerTypeAdapterFactory(GeocodingAdapterFactory.create()) .create(); diff --git a/services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/models/GeocodingResponse.java b/services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/models/GeocodingResponse.java index c269d0541..f0008418e 100644 --- a/services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/models/GeocodingResponse.java +++ b/services-geocoding/src/main/java/com/mapbox/api/geocoding/v5/models/GeocodingResponse.java @@ -7,13 +7,8 @@ import com.google.gson.TypeAdapter; import com.mapbox.geojson.BoundingBox; import com.mapbox.geojson.FeatureCollection; -import com.mapbox.geojson.Geometry; -import com.mapbox.geojson.Point; -import com.mapbox.geojson.gson.BoundingBoxDeserializer; -import com.mapbox.geojson.gson.BoundingBoxSerializer; -import com.mapbox.geojson.gson.GeometryDeserializer; -import com.mapbox.geojson.gson.GeometryTypeAdapter; -import com.mapbox.geojson.gson.PointDeserializer; +import com.mapbox.geojson.GeometryAdapterFactory; +import com.mapbox.geojson.gson.BoundingBoxTypeAdapter; import java.io.Serializable; import java.util.List; @@ -41,9 +36,8 @@ public abstract class GeocodingResponse implements Serializable { @NonNull public static GeocodingResponse fromJson(@NonNull String json) { Gson gson = new GsonBuilder() - .registerTypeAdapter(Point.class, new PointDeserializer()) - .registerTypeAdapter(Geometry.class, new GeometryDeserializer()) - .registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()) + .registerTypeAdapterFactory(GeometryAdapterFactory.create()) + .registerTypeAdapter(BoundingBox.class, new BoundingBoxTypeAdapter()) .registerTypeAdapterFactory(GeocodingAdapterFactory.create()) .create(); return gson.fromJson(json, GeocodingResponse.class); @@ -123,8 +117,8 @@ public static Builder builder() { @NonNull public String toJson() { Gson gson = new GsonBuilder() - .registerTypeAdapter(Geometry.class, new GeometryTypeAdapter()) - .registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()) + .registerTypeAdapterFactory(GeometryAdapterFactory.create()) + .registerTypeAdapter(BoundingBox.class, new BoundingBoxTypeAdapter()) .registerTypeAdapterFactory(GeocodingAdapterFactory.create()) .create(); return gson.toJson(this, GeocodingResponse.class); diff --git a/services-geocoding/src/test/java/com/mapbox/api/geocoding/v5/models/CarmenFeatureTest.java b/services-geocoding/src/test/java/com/mapbox/api/geocoding/v5/models/CarmenFeatureTest.java index fb8964970..2e6da2237 100644 --- a/services-geocoding/src/test/java/com/mapbox/api/geocoding/v5/models/CarmenFeatureTest.java +++ b/services-geocoding/src/test/java/com/mapbox/api/geocoding/v5/models/CarmenFeatureTest.java @@ -172,7 +172,7 @@ public void testNullProperties() { @Test public void testNullPropertiesJson() { - String jsonString = "{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[-77.0, 38.0]}}"; + String jsonString = "{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[-77.0,38.0]}}"; CarmenFeature feature = CarmenFeature.fromJson(jsonString); // Json( null Properties) -> Feature (empty Properties) -> Json(null Properties) diff --git a/services-geojson/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java b/services-geojson/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java new file mode 100644 index 000000000..2c93f1e3c --- /dev/null +++ b/services-geojson/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.gson.typeadapters; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.internal.Streams; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +/** + * Adapts values whose runtime type may differ from their declaration type. This + * is necessary when a field's type is not the same type that GSON should create + * when deserializing that field. For example, consider these types: + *
   {@code
+ *   abstract class Shape {
+ *     int x;
+ *     int y;
+ *   }
+ *   class Circle extends Shape {
+ *     int radius;
+ *   }
+ *   class Rectangle extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Diamond extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Drawing {
+ *     Shape bottomShape;
+ *     Shape topShape;
+ *   }
+ * }
+ *

Without additional type information, the serialized JSON is ambiguous. Is + * the bottom shape in this drawing a rectangle or a diamond?

   {@code
+ *   {
+ *     "bottomShape": {
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * This class addresses this problem by adding type information to the + * serialized JSON and honoring that type information when the JSON is + * deserialized:
   {@code
+ *   {
+ *     "bottomShape": {
+ *       "type": "Diamond",
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "type": "Circle",
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * Both the type field name ({@code "type"}) and the type labels ({@code + * "Rectangle"}) are configurable. + * + *

Registering Types

+ * Create a {@code RuntimeTypeAdapterFactory} by passing the base type and type field + * name to the {@link #of} factory method. If you don't supply an explicit type + * field name, {@code "type"} will be used.
   {@code
+ *   RuntimeTypeAdapterFactory shapeAdapterFactory
+ *       = RuntimeTypeAdapterFactory.of(Shape.class, "type");
+ * }
+ * Next register all of your subtypes. Every subtype must be explicitly + * registered. This protects your application from injection attacks. If you + * don't supply an explicit type label, the type's simple name will be used. + *
   {@code
+ *   shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle");
+ *   shapeAdapterFactory.registerSubtype(Circle.class, "Circle");
+ *   shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond");
+ * }
+ * Finally, register the type adapter factory in your application's GSON builder: + *
   {@code
+ *   Gson gson = new GsonBuilder()
+ *       .registerTypeAdapterFactory(shapeAdapterFactory)
+ *       .create();
+ * }
+ * Like {@code GsonBuilder}, this API supports chaining:
   {@code
+ *   RuntimeTypeAdapterFactory shapeAdapterFactory =
+ *     RuntimeTypeAdapterFactory.of(Shape.class)
+ *       .registerSubtype(Rectangle.class)
+ *       .registerSubtype(Circle.class)
+ *       .registerSubtype(Diamond.class);
+ * }
+ * + * @param base type for this factory + * @since 4.6.0 + */ +public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { + private final Class baseType; + private final String typeFieldName; + private final Map> labelToSubtype = new LinkedHashMap>(); + private final Map, String> subtypeToLabel = new LinkedHashMap, String>(); + private final boolean maintainType; + + private RuntimeTypeAdapterFactory(Class baseType, String typeFieldName, boolean maintainType) { + if (typeFieldName == null || baseType == null) { + throw new NullPointerException(); + } + this.baseType = baseType; + this.typeFieldName = typeFieldName; + this.maintainType = maintainType; + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + * {@code maintainType} flag decide if the type will be stored in pojo or not. + * + * @param base type + * @param baseType class of base type + * @param typeFieldName field name used to distinguish subtypes + * @param maintainType true if the type will be stored in pojo, false - otherwise + */ + public static RuntimeTypeAdapterFactory of(Class baseType, + String typeFieldName, + boolean maintainType) { + return new RuntimeTypeAdapterFactory(baseType, typeFieldName, maintainType); + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + * + * @param base type + * @param baseType class of base type + * @param typeFieldName field name used to distinguish subtypes + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) { + return new RuntimeTypeAdapterFactory(baseType, typeFieldName, false); + } + + /** + * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as + * the type field name. + * + * @param base type + * @param baseType class of base type + */ + public static RuntimeTypeAdapterFactory of(Class baseType) { + return new RuntimeTypeAdapterFactory(baseType, "type", false); + } + + /** + * Registers {@code type} identified by {@code label}. Labels are case + * sensitive. + * + * @param type class of subtype of base type + * @param label string value for field that distinguishes subtypes + * @throws IllegalArgumentException if either {@code type} or {@code label} + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type, String label) { + if (type == null || label == null) { + throw new NullPointerException(); + } + if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { + throw new IllegalArgumentException("types and labels must be unique"); + } + labelToSubtype.put(label, type); + subtypeToLabel.put(type, label); + return this; + } + + /** + * Registers {@code type} identified by its {@link Class#getSimpleName simple + * name}. Labels are case sensitive. + * + * @param type type name + * @throws IllegalArgumentException if either {@code type} or its simple name + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type) { + return registerSubtype(type, type.getSimpleName()); + } + + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (type.getRawType() != baseType) { + return null; + } + + final Map> labelToDelegate + = new LinkedHashMap>(); + final Map, TypeAdapter> subtypeToDelegate + = new LinkedHashMap, TypeAdapter>(); + for (Map.Entry> entry : labelToSubtype.entrySet()) { + TypeAdapter delegate = + gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); + labelToDelegate.put(entry.getKey(), delegate); + subtypeToDelegate.put(entry.getValue(), delegate); + } + + return new TypeAdapter() { + @Override public R read(JsonReader in) throws IOException { + JsonElement jsonElement = Streams.parse(in); + JsonElement labelJsonElement; + if (maintainType) { + labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName); + } else { + labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); + } + + if (labelJsonElement == null) { + throw new JsonParseException("cannot deserialize " + baseType + + " because it does not define a field named " + typeFieldName); + } + String label = labelJsonElement.getAsString(); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label); + if (delegate == null) { + throw new JsonParseException("cannot deserialize " + baseType + " subtype named " + + label + "; did you forget to register a subtype?"); + } + return delegate.fromJsonTree(jsonElement); + } + + @Override public void write(JsonWriter out, R value) throws IOException { + Class srcType = value.getClass(); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType); + if (delegate == null) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + "; did you forget to register a subtype?"); + } + JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); + + if (maintainType) { + Streams.write(jsonObject, out); + return; + } + + JsonObject clone = new JsonObject(); + + if (jsonObject.has(typeFieldName)) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + " because it already defines a field named " + typeFieldName); + } + String label = subtypeToLabel.get(srcType); + clone.add(typeFieldName, new JsonPrimitive(label)); + + for (Map.Entry e : jsonObject.entrySet()) { + clone.add(e.getKey(), e.getValue()); + } + Streams.write(clone, out); + } + }.nullSafe(); + } +} + diff --git a/services-geojson/src/main/java/com/google/gson/typeadapters/package-info.java b/services-geojson/src/main/java/com/google/gson/typeadapters/package-info.java new file mode 100644 index 000000000..3117c6cd8 --- /dev/null +++ b/services-geojson/src/main/java/com/google/gson/typeadapters/package-info.java @@ -0,0 +1,5 @@ +/** + * Contains Google gson type adapters. + */ + +package com.google.gson.typeadapters; diff --git a/services-geojson/src/main/java/com/mapbox/geojson/BaseCoordinatesTypeAdapter.java b/services-geojson/src/main/java/com/mapbox/geojson/BaseCoordinatesTypeAdapter.java new file mode 100644 index 000000000..6da74207a --- /dev/null +++ b/services-geojson/src/main/java/com/mapbox/geojson/BaseCoordinatesTypeAdapter.java @@ -0,0 +1,83 @@ +package com.mapbox.geojson; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.mapbox.geojson.exception.GeoJsonException; +import com.mapbox.geojson.shifter.CoordinateShifterManager; +import com.mapbox.geojson.utils.GeoJsonUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Base class for converting {@code T} instance of coordinates to JSON and + * JSON to instance of {@code T}. + * + * @param Type of coordinates + * @since 4.6.0 + */ +abstract class BaseCoordinatesTypeAdapter extends TypeAdapter { + + + protected void writePoint(JsonWriter out, Point value) throws IOException { + writePointList(out, value.coordinates()); + } + + protected Point readPoint(JsonReader in) throws IOException { + + List coordinates = readPointList(in); + if (coordinates != null && coordinates.size() > 1) { + return new Point("Point",null, coordinates); + } + + throw new GeoJsonException(" Point coordinates should be non-null double array"); + } + + + protected void writePointList(JsonWriter out, List value) throws IOException { + + if (value == null) { + return; + } + + out.beginArray(); + + // Unshift coordinates + List unshiftedCoordinates = + CoordinateShifterManager.getCoordinateShifter().unshiftPoint(value); + + out.value(GeoJsonUtils.trim(unshiftedCoordinates.get(0))); + out.value(GeoJsonUtils.trim(unshiftedCoordinates.get(1))); + + // Includes altitude + if (value.size() > 2) { + out.value(unshiftedCoordinates.get(2)); + } + out.endArray(); + } + + protected List readPointList(JsonReader in) throws IOException { + + if (in.peek() == JsonToken.NULL) { + throw new NullPointerException(); + } + + List coordinates = new ArrayList(); + in.beginArray(); + while (in.hasNext()) { + coordinates.add(in.nextDouble()); + } + in.endArray(); + + if (coordinates.size() > 2) { + return CoordinateShifterManager.getCoordinateShifter() + .shiftLonLatAlt(coordinates.get(0), coordinates.get(1), coordinates.get(2)); + } + return CoordinateShifterManager.getCoordinateShifter() + .shiftLonLat(coordinates.get(0), coordinates.get(1)); + } + +} diff --git a/services-geojson/src/main/java/com/mapbox/geojson/BaseGeometryTypeAdapter.java b/services-geojson/src/main/java/com/mapbox/geojson/BaseGeometryTypeAdapter.java new file mode 100644 index 000000000..b1c7b3c4d --- /dev/null +++ b/services-geojson/src/main/java/com/mapbox/geojson/BaseGeometryTypeAdapter.java @@ -0,0 +1,134 @@ +package com.mapbox.geojson; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.mapbox.geojson.exception.GeoJsonException; +import com.mapbox.geojson.gson.BoundingBoxTypeAdapter; + +import java.io.IOException; + +/** + * Base class for converting {@code Geometry} instances to JSON and + * JSON to instances of {@code Geometry}. + * + * @param Geometry + * @param Type of coordinates + * @since 4.6.0 + */ +abstract class BaseGeometryTypeAdapter extends TypeAdapter { + + private volatile TypeAdapter stringAdapter; + private volatile TypeAdapter boundingBoxAdapter; + private volatile TypeAdapter coordinatesAdapter; + + private final Gson gson; + + BaseGeometryTypeAdapter(Gson gson, TypeAdapter coordinatesAdapter) { + this.gson = gson; + this.coordinatesAdapter = coordinatesAdapter; + this.boundingBoxAdapter = new BoundingBoxTypeAdapter(); + } + + public void writeCoordinateContainer(JsonWriter jsonWriter, CoordinateContainer object) + throws IOException { + if (object == null) { + jsonWriter.nullValue(); + return; + } + jsonWriter.beginObject(); + jsonWriter.name("type"); + if (object.type() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter stringAdapter = this.stringAdapter; + if (stringAdapter == null) { + stringAdapter = gson.getAdapter(String.class); + this.stringAdapter = stringAdapter; + } + stringAdapter.write(jsonWriter, object.type()); + } + jsonWriter.name("bbox"); + if (object.bbox() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter boundingBoxAdapter = this.boundingBoxAdapter; + if (boundingBoxAdapter == null) { + boundingBoxAdapter = gson.getAdapter(BoundingBox.class); + this.boundingBoxAdapter = boundingBoxAdapter; + } + boundingBoxAdapter.write(jsonWriter, object.bbox()); + } + jsonWriter.name("coordinates"); + if (object.coordinates() == null) { + jsonWriter.nullValue(); + } else { + TypeAdapter coordinatesAdapter = this.coordinatesAdapter; + if (coordinatesAdapter == null) { + throw new GeoJsonException("Coordinates type adapter is null"); + } + coordinatesAdapter.write(jsonWriter, object.coordinates()); + } + jsonWriter.endObject(); + } + + public CoordinateContainer readCoordinateContainer(JsonReader jsonReader) throws IOException { + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + return null; + } + + jsonReader.beginObject(); + String type = null; + BoundingBox bbox = null; + T coordinates = null; + + while (jsonReader.hasNext()) { + String name = jsonReader.nextName(); + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + continue; + } + switch (name) { + case "type": + TypeAdapter stringAdapter = this.stringAdapter; + if (stringAdapter == null) { + stringAdapter = gson.getAdapter(String.class); + this.stringAdapter = stringAdapter; + } + type = stringAdapter.read(jsonReader); + break; + + case "bbox": + TypeAdapter boundingBoxAdapter = this.boundingBoxAdapter; + if (boundingBoxAdapter == null) { + boundingBoxAdapter = gson.getAdapter(BoundingBox.class); + this.boundingBoxAdapter = boundingBoxAdapter; + } + bbox = boundingBoxAdapter.read(jsonReader); + break; + + case "coordinates": + TypeAdapter coordinatesAdapter = this.coordinatesAdapter; + if (coordinatesAdapter == null) { + throw new GeoJsonException("Coordinates type adapter is null"); + } + coordinates = coordinatesAdapter.read(jsonReader); + break; + + default: + jsonReader.skipValue(); + + } + } + jsonReader.endObject(); + + return createCoordinateContainer(type, bbox, coordinates); + } + + abstract CoordinateContainer createCoordinateContainer(String type, + BoundingBox bbox, + T coordinates); +} diff --git a/services-geojson/src/main/java/com/mapbox/geojson/BoundingBox.java b/services-geojson/src/main/java/com/mapbox/geojson/BoundingBox.java index 339debb73..45c6a7f97 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/BoundingBox.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/BoundingBox.java @@ -9,9 +9,7 @@ import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; import com.mapbox.geojson.constants.GeoJsonConstants; -import com.mapbox.geojson.gson.BoundingBoxDeserializer; -import com.mapbox.geojson.gson.BoundingBoxSerializer; -import com.mapbox.geojson.gson.GeoJsonAdapterFactory; +import com.mapbox.geojson.gson.BoundingBoxTypeAdapter; import java.io.Serializable; @@ -46,8 +44,7 @@ public class BoundingBox implements Serializable { */ public static BoundingBox fromJson(String json) { Gson gson = new GsonBuilder() - .registerTypeAdapterFactory(GeoJsonAdapterFactory.create()) - .registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()) + .registerTypeAdapter(BoundingBox.class, new BoundingBoxTypeAdapter()) .create(); return gson.fromJson(json, BoundingBox.class); } @@ -176,6 +173,7 @@ public static BoundingBox fromLngLats( } this.northeast = northeast; } + /** * Provides the {@link Point} which represents the southwest corner of this bounding box when the * map is facing due north. @@ -252,7 +250,7 @@ public final double north() { * @since 3.0.0 */ public static TypeAdapter typeAdapter(Gson gson) { - return null; //new BoundingBox.GsonTypeAdapter(gson); + return new BoundingBoxTypeAdapter(); } /** @@ -264,7 +262,7 @@ public static TypeAdapter typeAdapter(Gson gson) { */ public final String toJson() { Gson gson = new GsonBuilder() - .registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()) + .registerTypeAdapter(BoundingBox.class, new BoundingBoxTypeAdapter()) .create(); return gson.toJson(this, BoundingBox.class); } @@ -278,12 +276,12 @@ public String toString() { } @Override - public boolean equals(Object o) { - if (o == this) { + public boolean equals(Object obj) { + if (obj == this) { return true; } - if (o instanceof BoundingBox) { - BoundingBox that = (BoundingBox) o; + if (obj instanceof BoundingBox) { + BoundingBox that = (BoundingBox) obj; return (this.southwest.equals(that.southwest())) && (this.northeast.equals(that.northeast())); } @@ -292,11 +290,11 @@ public boolean equals(Object o) { @Override public int hashCode() { - int h$ = 1; - h$ *= 1000003; - h$ ^= southwest.hashCode(); - h$ *= 1000003; - h$ ^= northeast.hashCode(); - return h$; + int hashCode = 1; + hashCode *= 1000003; + hashCode ^= southwest.hashCode(); + hashCode *= 1000003; + hashCode ^= northeast.hashCode(); + return hashCode; } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/CoordinateContainer.java b/services-geojson/src/main/java/com/mapbox/geojson/CoordinateContainer.java index 4f040a193..43d80180a 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/CoordinateContainer.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/CoordinateContainer.java @@ -18,4 +18,5 @@ public interface CoordinateContainer extends Geometry { * @since 3.0.0 */ T coordinates(); + } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/Feature.java b/services-geojson/src/main/java/com/mapbox/geojson/Feature.java index 4a131102c..45a2c58a1 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/Feature.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/Feature.java @@ -7,17 +7,12 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; -import com.google.gson.typeadapters.RuntimeTypeAdapterFactory; -import com.mapbox.geojson.gson.BoundingBoxDeserializer; -import com.mapbox.geojson.gson.BoundingBoxSerializer; +import com.mapbox.geojson.gson.BoundingBoxTypeAdapter; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; -import com.mapbox.geojson.gson.GeometryDeserializer; -import com.mapbox.geojson.gson.GeometryTypeAdapter; -import com.mapbox.geojson.gson.PointDeserializer; -import com.mapbox.geojson.gson.PointSerializer; import java.io.IOException; @@ -57,6 +52,7 @@ public final class Feature implements GeoJson { private final String type; + @JsonAdapter(BoundingBoxTypeAdapter.class) private final BoundingBox bbox; private final String id; @@ -78,12 +74,8 @@ public final class Feature implements GeoJson { public static Feature fromJson(@NonNull String json) { GsonBuilder gson = new GsonBuilder(); - - gson.registerTypeAdapter(Point.class, new PointDeserializer()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); - gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); - gson.registerTypeAdapter(Geometry.class, new GeometryDeserializer()); + gson.registerTypeAdapterFactory(GeometryAdapterFactory.create()); Feature feature = gson.create().fromJson(json, Feature.class); @@ -277,9 +269,11 @@ public JsonObject properties() { @Override public String toJson() { - GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapter(Geometry.class, new GeometryTypeAdapter()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()); + Gson gson = new GsonBuilder() + .registerTypeAdapterFactory(GeoJsonAdapterFactory.create()) + .registerTypeAdapterFactory(GeometryAdapterFactory.create()) + .create(); + // Empty properties -> should not appear in json string Feature feature = this; @@ -287,7 +281,7 @@ public String toJson() { feature = new Feature(TYPE, bbox(), id(), geometry(), null); } - return gson.create().toJson(feature); + return gson.toJson(feature); } /** @@ -456,48 +450,56 @@ public String toString() { } @Override - public boolean equals(Object o) { - if (o == this) { + public boolean equals(Object obj) { + if (obj == this) { return true; } - if (o instanceof Feature) { - Feature that = (Feature) o; + if (obj instanceof Feature) { + Feature that = (Feature) obj; return (this.type.equals(that.type())) && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) && ((this.id == null) ? (that.id() == null) : this.id.equals(that.id())) - && ((this.geometry == null) ? (that.geometry() == null) : this.geometry.equals(that.geometry())) - && ((this.properties == null) ? (that.properties() == null) : this.properties.equals(that.properties())); + && ((this.geometry == null) + ? (that.geometry() == null) : this.geometry.equals(that.geometry())) + && ((this.properties == null) + ? (that.properties() == null) : this.properties.equals(that.properties())); } return false; } @Override public int hashCode() { - int h$ = 1; - h$ *= 1000003; - h$ ^= type.hashCode(); - h$ *= 1000003; - h$ ^= (bbox == null) ? 0 : bbox.hashCode(); - h$ *= 1000003; - h$ ^= (id == null) ? 0 : id.hashCode(); - h$ *= 1000003; - h$ ^= (geometry == null) ? 0 : geometry.hashCode(); - h$ *= 1000003; - h$ ^= (properties == null) ? 0 : properties.hashCode(); - return h$; - } - - public static final class GsonTypeAdapter extends TypeAdapter { - private volatile TypeAdapter string_adapter; - private volatile TypeAdapter boundingBox_adapter; - private volatile TypeAdapter geometry_adapter; - private volatile TypeAdapter jsonObject_adapter; + int hashCode = 1; + hashCode *= 1000003; + hashCode ^= type.hashCode(); + hashCode *= 1000003; + hashCode ^= (bbox == null) ? 0 : bbox.hashCode(); + hashCode *= 1000003; + hashCode ^= (id == null) ? 0 : id.hashCode(); + hashCode *= 1000003; + hashCode ^= (geometry == null) ? 0 : geometry.hashCode(); + hashCode *= 1000003; + hashCode ^= (properties == null) ? 0 : properties.hashCode(); + return hashCode; + } + + /** + * TypeAdapter to serialize/deserialize Feature objects. + * + * @since 4.6.0 + */ + static final class GsonTypeAdapter extends TypeAdapter { + private volatile TypeAdapter stringTypeAdapter; + private volatile TypeAdapter boundingBoxTypeAdapter; + private volatile TypeAdapter geometryTypeAdapter; + private volatile TypeAdapter jsonObjectTypeAdapter; private final Gson gson; - public GsonTypeAdapter(Gson gson) { + + GsonTypeAdapter(Gson gson) { this.gson = gson; } + @Override - @SuppressWarnings("unchecked") public void write(JsonWriter jsonWriter, Feature object) throws IOException { if (object == null) { jsonWriter.nullValue(); @@ -508,56 +510,61 @@ public void write(JsonWriter jsonWriter, Feature object) throws IOException { if (object.type() == null) { jsonWriter.nullValue(); } else { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); + TypeAdapter stringTypeAdapter = this.stringTypeAdapter; + if (stringTypeAdapter == null) { + stringTypeAdapter = gson.getAdapter(String.class); + this.stringTypeAdapter = stringTypeAdapter; } - string_adapter.write(jsonWriter, object.type()); + stringTypeAdapter.write(jsonWriter, object.type()); } jsonWriter.name("bbox"); if (object.bbox() == null) { jsonWriter.nullValue(); } else { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + TypeAdapter boundingBoxTypeAdapter = this.boundingBoxTypeAdapter; + if (boundingBoxTypeAdapter == null) { + boundingBoxTypeAdapter = gson.getAdapter(BoundingBox.class); + this.boundingBoxTypeAdapter = boundingBoxTypeAdapter; } - boundingBox_adapter.write(jsonWriter, object.bbox()); + boundingBoxTypeAdapter.write(jsonWriter, object.bbox()); } jsonWriter.name("id"); if (object.id() == null) { jsonWriter.nullValue(); } else { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); + TypeAdapter stringTypeAdapter = this.stringTypeAdapter; + if (stringTypeAdapter == null) { + stringTypeAdapter = gson.getAdapter(String.class); + this.stringTypeAdapter = stringTypeAdapter; } - string_adapter.write(jsonWriter, object.id()); + stringTypeAdapter.write(jsonWriter, object.id()); } jsonWriter.name("geometry"); if (object.geometry() == null) { jsonWriter.nullValue(); } else { - TypeAdapter geometry_adapter = this.geometry_adapter; - if (geometry_adapter == null) { - this.geometry_adapter = geometry_adapter = gson.getAdapter(Geometry.class); + TypeAdapter geometryTypeAdapter = this.geometryTypeAdapter; + if (geometryTypeAdapter == null) { + geometryTypeAdapter = gson.getAdapter(Geometry.class); + this.geometryTypeAdapter = geometryTypeAdapter; } - geometry_adapter.write(jsonWriter, object.geometry()); + geometryTypeAdapter.write(jsonWriter, object.geometry()); } jsonWriter.name("properties"); if (object.properties() == null) { jsonWriter.nullValue(); } else { - TypeAdapter jsonObject_adapter = this.jsonObject_adapter; - if (jsonObject_adapter == null) { - this.jsonObject_adapter = jsonObject_adapter = gson.getAdapter(JsonObject.class); + TypeAdapter jsonObjectTypeAdapter = this.jsonObjectTypeAdapter; + if (jsonObjectTypeAdapter == null) { + jsonObjectTypeAdapter = gson.getAdapter(JsonObject.class); + this.jsonObjectTypeAdapter = jsonObjectTypeAdapter; } - jsonObject_adapter.write(jsonWriter, object.properties()); + jsonObjectTypeAdapter.write(jsonWriter, object.properties()); } jsonWriter.endObject(); } + @Override - @SuppressWarnings("unchecked") public Feature read(JsonReader jsonReader) throws IOException { if (jsonReader.peek() == JsonToken.NULL) { jsonReader.nextNull(); @@ -570,55 +577,60 @@ public Feature read(JsonReader jsonReader) throws IOException { Geometry geometry = null; JsonObject properties = null; while (jsonReader.hasNext()) { - String _name = jsonReader.nextName(); + String name = jsonReader.nextName(); if (jsonReader.peek() == JsonToken.NULL) { jsonReader.nextNull(); continue; } - switch (_name) { - case "type": { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); + switch (name) { + case "type": + TypeAdapter strTypeAdapter = this.stringTypeAdapter; + if (strTypeAdapter == null) { + strTypeAdapter = gson.getAdapter(String.class); + this.stringTypeAdapter = strTypeAdapter; } - type = string_adapter.read(jsonReader); + type = strTypeAdapter.read(jsonReader); break; - } - case "bbox": { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + + case "bbox": + TypeAdapter boundingBoxTypeAdapter = this.boundingBoxTypeAdapter; + if (boundingBoxTypeAdapter == null) { + boundingBoxTypeAdapter = gson.getAdapter(BoundingBox.class); + this.boundingBoxTypeAdapter = boundingBoxTypeAdapter; } - bbox = boundingBox_adapter.read(jsonReader); + bbox = boundingBoxTypeAdapter.read(jsonReader); break; - } - case "id": { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); + + case "id": + strTypeAdapter = this.stringTypeAdapter; + if (strTypeAdapter == null) { + strTypeAdapter = gson.getAdapter(String.class); + this.stringTypeAdapter = strTypeAdapter; } - id = string_adapter.read(jsonReader); + id = strTypeAdapter.read(jsonReader); break; - } - case "geometry": { - TypeAdapter geometry_adapter = this.geometry_adapter; - if (geometry_adapter == null) { - this.geometry_adapter = geometry_adapter = gson.getAdapter(Geometry.class); + + case "geometry": + TypeAdapter geometryTypeAdapter = this.geometryTypeAdapter; + if (geometryTypeAdapter == null) { + geometryTypeAdapter = gson.getAdapter(Geometry.class); + this.geometryTypeAdapter = geometryTypeAdapter; } - geometry = geometry_adapter.read(jsonReader); + geometry = geometryTypeAdapter.read(jsonReader); break; - } - case "properties": { - TypeAdapter jsonObject_adapter = this.jsonObject_adapter; - if (jsonObject_adapter == null) { - this.jsonObject_adapter = jsonObject_adapter = gson.getAdapter(JsonObject.class); + + case "properties": + TypeAdapter jsonObjectTypeAdapter = this.jsonObjectTypeAdapter; + if (jsonObjectTypeAdapter == null) { + jsonObjectTypeAdapter = gson.getAdapter(JsonObject.class); + this.jsonObjectTypeAdapter = jsonObjectTypeAdapter; } - properties = jsonObject_adapter.read(jsonReader); + properties = jsonObjectTypeAdapter.read(jsonReader); break; - } - default: { + + default: jsonReader.skipValue(); - } + } } jsonReader.endObject(); diff --git a/services-geojson/src/main/java/com/mapbox/geojson/FeatureCollection.java b/services-geojson/src/main/java/com/mapbox/geojson/FeatureCollection.java index 5fea09704..a121deb52 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/FeatureCollection.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/FeatureCollection.java @@ -5,18 +5,13 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; -import com.google.gson.typeadapters.RuntimeTypeAdapterFactory; -import com.mapbox.geojson.gson.BoundingBoxDeserializer; -import com.mapbox.geojson.gson.BoundingBoxSerializer; +import com.mapbox.geojson.gson.BoundingBoxTypeAdapter; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; -import com.mapbox.geojson.gson.GeometryDeserializer; -import com.mapbox.geojson.gson.GeometryTypeAdapter; -import com.mapbox.geojson.gson.PointDeserializer; -import com.mapbox.geojson.gson.PointSerializer; import java.io.IOException; import java.util.Arrays; @@ -48,6 +43,7 @@ public final class FeatureCollection implements GeoJson { private final String type; + @JsonAdapter(BoundingBoxTypeAdapter.class) private final BoundingBox bbox; private final List features; @@ -63,25 +59,10 @@ public final class FeatureCollection implements GeoJson { * @since 1.0.0 */ public static FeatureCollection fromJson(@NonNull String json) { -// final RuntimeTypeAdapterFactory geometryFactory = RuntimeTypeAdapterFactory -// .of(Geometry.class, "type") -// .registerSubtype(GeometryCollection.class, "GeometryCollection") -// .registerSubtype(Point.class, "Point") -// .registerSubtype(MultiPoint.class, "MultiPoint") -// .registerSubtype(LineString.class, "LineString") -// .registerSubtype(MultiLineString.class, "MultiLineString") -// .registerSubtype(Polygon.class, "Polygon") -// .registerSubtype(MultiPolygon.class, "MultiPolygon"); GsonBuilder gson = new GsonBuilder(); - //gson.registerTypeAdapterFactory(geometryFactory); - - gson.registerTypeAdapter(Point.class, new PointDeserializer()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); - gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); - gson.registerTypeAdapter(Geometry.class, new GeometryDeserializer()); - + gson.registerTypeAdapterFactory(GeometryAdapterFactory.create()); return gson.create().fromJson(json, FeatureCollection.class); } @@ -235,10 +216,8 @@ public List features() { public String toJson() { GsonBuilder gson = new GsonBuilder(); - - gson.registerTypeAdapter(Geometry.class, new GeometryTypeAdapter()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()); - + gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); + gson.registerTypeAdapterFactory(GeometryAdapterFactory.create()); return gson.create().toJson(this); } @@ -263,41 +242,48 @@ public String toString() { } @Override - public boolean equals(Object o) { - if (o == this) { + public boolean equals(Object obj) { + if (obj == this) { return true; } - if (o instanceof FeatureCollection) { - FeatureCollection that = (FeatureCollection) o; + if (obj instanceof FeatureCollection) { + FeatureCollection that = (FeatureCollection) obj; return (this.type.equals(that.type())) && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) - && ((this.features == null) ? (that.features() == null) : this.features.equals(that.features())); + && ((this.features == null) + ? (that.features() == null) : this.features.equals(that.features())); } return false; } @Override public int hashCode() { - int h$ = 1; - h$ *= 1000003; - h$ ^= type.hashCode(); - h$ *= 1000003; - h$ ^= (bbox == null) ? 0 : bbox.hashCode(); - h$ *= 1000003; - h$ ^= (features == null) ? 0 : features.hashCode(); - return h$; + int hashCode = 1; + hashCode *= 1000003; + hashCode ^= type.hashCode(); + hashCode *= 1000003; + hashCode ^= (bbox == null) ? 0 : bbox.hashCode(); + hashCode *= 1000003; + hashCode ^= (features == null) ? 0 : features.hashCode(); + return hashCode; } - public static final class GsonTypeAdapter extends TypeAdapter { - private volatile TypeAdapter string_adapter; - private volatile TypeAdapter boundingBox_adapter; - private volatile TypeAdapter> list__feature_adapter; + /** + * TypeAdapter to serialize/deserialize FeatureCollection objects. + * + * @since 4.6.0 + */ + static final class GsonTypeAdapter extends TypeAdapter { + private volatile TypeAdapter stringAdapter; + private volatile TypeAdapter boundingBoxAdapter; + private volatile TypeAdapter> listFeatureAdapter; private final Gson gson; - public GsonTypeAdapter(Gson gson) { + + GsonTypeAdapter(Gson gson) { this.gson = gson; } + @Override - @SuppressWarnings("unchecked") public void write(JsonWriter jsonWriter, FeatureCollection object) throws IOException { if (object == null) { jsonWriter.nullValue(); @@ -308,36 +294,41 @@ public void write(JsonWriter jsonWriter, FeatureCollection object) throws IOExce if (object.type() == null) { jsonWriter.nullValue(); } else { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); + TypeAdapter stringAdapter = this.stringAdapter; + if (stringAdapter == null) { + stringAdapter = gson.getAdapter(String.class); + this.stringAdapter = stringAdapter; } - string_adapter.write(jsonWriter, object.type()); + stringAdapter.write(jsonWriter, object.type()); } jsonWriter.name("bbox"); if (object.bbox() == null) { jsonWriter.nullValue(); } else { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + TypeAdapter boundingBoxTypeAdapter = this.boundingBoxAdapter; + if (boundingBoxTypeAdapter == null) { + boundingBoxTypeAdapter = gson.getAdapter(BoundingBox.class); + this.boundingBoxAdapter = boundingBoxTypeAdapter; } - boundingBox_adapter.write(jsonWriter, object.bbox()); + boundingBoxTypeAdapter.write(jsonWriter, object.bbox()); } jsonWriter.name("features"); if (object.features() == null) { jsonWriter.nullValue(); } else { - TypeAdapter> list__feature_adapter = this.list__feature_adapter; - if (list__feature_adapter == null) { - this.list__feature_adapter = list__feature_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Feature.class)); + TypeAdapter> listFeatureAdapter = this.listFeatureAdapter; + if (listFeatureAdapter == null) { + TypeToken typeToken = TypeToken.getParameterized(List.class, Feature.class); + listFeatureAdapter = + (TypeAdapter>) gson.getAdapter(typeToken); + this.listFeatureAdapter = listFeatureAdapter; } - list__feature_adapter.write(jsonWriter, object.features()); + listFeatureAdapter.write(jsonWriter, object.features()); } jsonWriter.endObject(); } + @Override - @SuppressWarnings("unchecked") public FeatureCollection read(JsonReader jsonReader) throws IOException { if (jsonReader.peek() == JsonToken.NULL) { jsonReader.nextNull(); @@ -348,39 +339,44 @@ public FeatureCollection read(JsonReader jsonReader) throws IOException { BoundingBox bbox = null; List features = null; while (jsonReader.hasNext()) { - String _name = jsonReader.nextName(); + String name = jsonReader.nextName(); if (jsonReader.peek() == JsonToken.NULL) { jsonReader.nextNull(); continue; } - switch (_name) { - case "type": { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); + switch (name) { + case "type": + TypeAdapter stringAdapter = this.stringAdapter; + if (stringAdapter == null) { + stringAdapter = gson.getAdapter(String.class); + this.stringAdapter = stringAdapter; } - type = string_adapter.read(jsonReader); + type = stringAdapter.read(jsonReader); break; - } - case "bbox": { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + + case "bbox": + TypeAdapter boundingBoxAdapter = this.boundingBoxAdapter; + if (boundingBoxAdapter == null) { + boundingBoxAdapter = gson.getAdapter(BoundingBox.class); + this.boundingBoxAdapter = boundingBoxAdapter; } - bbox = boundingBox_adapter.read(jsonReader); + bbox = boundingBoxAdapter.read(jsonReader); break; - } - case "features": { - TypeAdapter> list__feature_adapter = this.list__feature_adapter; - if (list__feature_adapter == null) { - this.list__feature_adapter = list__feature_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Feature.class)); + + case "features": + TypeAdapter> listFeatureAdapter = this.listFeatureAdapter; + if (listFeatureAdapter == null) { + TypeToken typeToken = TypeToken.getParameterized(List.class, Feature.class); + listFeatureAdapter = + (TypeAdapter>) gson.getAdapter(typeToken); + this.listFeatureAdapter = listFeatureAdapter; } - features = list__feature_adapter.read(jsonReader); + features = listFeatureAdapter.read(jsonReader); break; - } - default: { + + default: jsonReader.skipValue(); - } + } } jsonReader.endObject(); diff --git a/services-geojson/src/main/java/com/mapbox/geojson/GeometryAdapterFactory.java b/services-geojson/src/main/java/com/mapbox/geojson/GeometryAdapterFactory.java new file mode 100644 index 000000000..5e6a283a1 --- /dev/null +++ b/services-geojson/src/main/java/com/mapbox/geojson/GeometryAdapterFactory.java @@ -0,0 +1,37 @@ +package com.mapbox.geojson; + +import com.google.gson.TypeAdapterFactory; + +import com.google.gson.typeadapters.RuntimeTypeAdapterFactory; + +/** + * A Geometry type adapter factory for convenience for serialization/deserialization. + * @since 4.6.0 + */ +public abstract class GeometryAdapterFactory implements TypeAdapterFactory { + + private static TypeAdapterFactory geometryTypeFactory; + + + /** + * Create a new instance of Geometry type adapter factory, this is passed into the Gson + * Builder. + * + * @return a new GSON TypeAdapterFactory + * @since 4.4.0 + */ + public static TypeAdapterFactory create() { + + if (geometryTypeFactory == null) { + geometryTypeFactory = RuntimeTypeAdapterFactory.of(Geometry.class, "type", true) + .registerSubtype(GeometryCollection.class, "GeometryCollection") + .registerSubtype(Point.class, "Point") + .registerSubtype(MultiPoint.class, "MultiPoint") + .registerSubtype(LineString.class, "LineString") + .registerSubtype(MultiLineString.class, "MultiLineString") + .registerSubtype(Polygon.class, "Polygon") + .registerSubtype(MultiPolygon.class, "MultiPolygon"); + } + return geometryTypeFactory; + } +} diff --git a/services-geojson/src/main/java/com/mapbox/geojson/GeometryCollection.java b/services-geojson/src/main/java/com/mapbox/geojson/GeometryCollection.java index ac988df49..bf8eb2ab7 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/GeometryCollection.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/GeometryCollection.java @@ -10,14 +10,7 @@ import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; -import com.google.gson.typeadapters.RuntimeTypeAdapterFactory; -import com.mapbox.geojson.gson.BoundingBoxDeserializer; -import com.mapbox.geojson.gson.BoundingBoxSerializer; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; -import com.mapbox.geojson.gson.GeometryDeserializer; -import com.mapbox.geojson.gson.GeometryTypeAdapter; -import com.mapbox.geojson.gson.PointDeserializer; -import com.mapbox.geojson.gson.PointSerializer; import java.io.IOException; import java.io.Serializable; @@ -88,25 +81,9 @@ public final class GeometryCollection implements Geometry, Serializable { */ public static GeometryCollection fromJson(String json) { -// final RuntimeTypeAdapterFactory geometryFactory = RuntimeTypeAdapterFactory -// .of(Geometry.class, "type") -// .registerSubtype(GeometryCollection.class, "GeometryCollection") -// .registerSubtype(Point.class, "Point") -// .registerSubtype(MultiPoint.class, "MultiPoint") -// .registerSubtype(LineString.class, "LineString") -// .registerSubtype(MultiLineString.class, "MultiLineString") -// .registerSubtype(Polygon.class, "Polygon") -// .registerSubtype(MultiPolygon.class, "MultiPolygon"); - GsonBuilder gson = new GsonBuilder(); -// gson.registerTypeAdapterFactory(geometryFactory); - - gson.registerTypeAdapter(Point.class, new PointDeserializer()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); - gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); - gson.registerTypeAdapter(Geometry.class, new GeometryDeserializer()); - + gson.registerTypeAdapterFactory(GeometryAdapterFactory.create()); return gson.create().fromJson(json, GeometryCollection.class); } @@ -164,6 +141,16 @@ public static GeometryCollection fromGeometry(@NonNull Geometry geometry, return new GeometryCollection(TYPE, bbox, geometries); } + /** + * Create a new instance of this class by giving the collection a list of {@link Geometry} and + * bounding box. + * + * @param geometries a non-null list of geometry which makes up this collection + * @param bbox optionally include a bbox definition as a double array + * @return a new instance of this class defined by the values passed inside this static factory + * method + * @since 4.6.0 + */ GeometryCollection(String type, @Nullable BoundingBox bbox, List geometries) { if (type == null) { throw new NullPointerException("Null type"); @@ -228,23 +215,9 @@ public List geometries() { */ @Override public String toJson() { - -// final RuntimeTypeAdapterFactory geometryFactory = RuntimeTypeAdapterFactory -// .of(Geometry.class, "type") -// .registerSubtype(GeometryCollection.class, "GeometryCollection") -// .registerSubtype(Point.class, "Point") -// .registerSubtype(MultiPoint.class, "MultiPoint") -// .registerSubtype(LineString.class, "LineString") -// .registerSubtype(MultiLineString.class, "MultiLineString") -// .registerSubtype(Polygon.class, "Polygon") -// .registerSubtype(MultiPolygon.class, "MultiPolygon"); - GsonBuilder gson = new GsonBuilder(); - // gson.registerTypeAdapterFactory(geometryFactory); - - gson.registerTypeAdapter(Geometry.class, new GeometryTypeAdapter()); - // gson.registerTypeAdapter(Point.class, new PointSerializer()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()); + gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); + gson.registerTypeAdapterFactory(GeometryAdapterFactory.create()); return gson.create().toJson(this); } @@ -269,12 +242,12 @@ public String toString() { } @Override - public boolean equals(Object o) { - if (o == this) { + public boolean equals(Object obj) { + if (obj == this) { return true; } - if (o instanceof GeometryCollection) { - GeometryCollection that = (GeometryCollection) o; + if (obj instanceof GeometryCollection) { + GeometryCollection that = (GeometryCollection) obj; return (this.type.equals(that.type())) && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) && (this.geometries.equals(that.geometries())); @@ -284,26 +257,32 @@ public boolean equals(Object o) { @Override public int hashCode() { - int h$ = 1; - h$ *= 1000003; - h$ ^= type.hashCode(); - h$ *= 1000003; - h$ ^= (bbox == null) ? 0 : bbox.hashCode(); - h$ *= 1000003; - h$ ^= geometries.hashCode(); - return h$; + int hashCode = 1; + hashCode *= 1000003; + hashCode ^= type.hashCode(); + hashCode *= 1000003; + hashCode ^= (bbox == null) ? 0 : bbox.hashCode(); + hashCode *= 1000003; + hashCode ^= geometries.hashCode(); + return hashCode; } - public static final class GsonTypeAdapter extends TypeAdapter { - private volatile TypeAdapter string_adapter; - private volatile TypeAdapter boundingBox_adapter; - private volatile TypeAdapter> list__geometry_adapter; + /** + * TypeAdapter to serialize/deserialize GeometryCollection objects. + * + * @since 4.6.0 + */ + static final class GsonTypeAdapter extends TypeAdapter { + private volatile TypeAdapter stringTypeAdapter; + private volatile TypeAdapter boundingBoxTypeAdapter; + private volatile TypeAdapter> listGeometryAdapter; private final Gson gson; - public GsonTypeAdapter(Gson gson) { + + GsonTypeAdapter(Gson gson) { this.gson = gson; } + @Override - @SuppressWarnings("unchecked") public void write(JsonWriter jsonWriter, GeometryCollection object) throws IOException { if (object == null) { jsonWriter.nullValue(); @@ -314,36 +293,41 @@ public void write(JsonWriter jsonWriter, GeometryCollection object) throws IOExc if (object.type() == null) { jsonWriter.nullValue(); } else { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); + TypeAdapter stringTypeAdapter = this.stringTypeAdapter; + if (stringTypeAdapter == null) { + stringTypeAdapter = gson.getAdapter(String.class); + this.stringTypeAdapter = stringTypeAdapter; } - string_adapter.write(jsonWriter, object.type()); + stringTypeAdapter.write(jsonWriter, object.type()); } jsonWriter.name("bbox"); if (object.bbox() == null) { jsonWriter.nullValue(); } else { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + TypeAdapter boundingBoxTypeAdapter = this.boundingBoxTypeAdapter; + if (boundingBoxTypeAdapter == null) { + boundingBoxTypeAdapter = gson.getAdapter(BoundingBox.class); + this.boundingBoxTypeAdapter = boundingBoxTypeAdapter; } - boundingBox_adapter.write(jsonWriter, object.bbox()); + boundingBoxTypeAdapter.write(jsonWriter, object.bbox()); } jsonWriter.name("geometries"); if (object.geometries() == null) { jsonWriter.nullValue(); } else { - TypeAdapter> list__geometry_adapter = this.list__geometry_adapter; - if (list__geometry_adapter == null) { - this.list__geometry_adapter = list__geometry_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Geometry.class)); + TypeAdapter> listGeometryAdapter = this.listGeometryAdapter; + if (listGeometryAdapter == null) { + TypeToken typeToken = TypeToken.getParameterized(List.class, Geometry.class); + listGeometryAdapter = + (TypeAdapter>) gson.getAdapter(typeToken); + this.listGeometryAdapter = listGeometryAdapter; } - list__geometry_adapter.write(jsonWriter, object.geometries()); + listGeometryAdapter.write(jsonWriter, object.geometries()); } jsonWriter.endObject(); } + @Override - @SuppressWarnings("unchecked") public GeometryCollection read(JsonReader jsonReader) throws IOException { if (jsonReader.peek() == JsonToken.NULL) { jsonReader.nextNull(); @@ -354,39 +338,44 @@ public GeometryCollection read(JsonReader jsonReader) throws IOException { BoundingBox bbox = null; List geometries = null; while (jsonReader.hasNext()) { - String _name = jsonReader.nextName(); + String name = jsonReader.nextName(); if (jsonReader.peek() == JsonToken.NULL) { jsonReader.nextNull(); continue; } - switch (_name) { - case "type": { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); + switch (name) { + case "type": + TypeAdapter stringTypeAdapter = this.stringTypeAdapter; + if (stringTypeAdapter == null) { + stringTypeAdapter = gson.getAdapter(String.class); + this.stringTypeAdapter = stringTypeAdapter; } - type = string_adapter.read(jsonReader); + type = stringTypeAdapter.read(jsonReader); break; - } - case "bbox": { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); + + case "bbox": + TypeAdapter boundingBoxTypeAdapter = this.boundingBoxTypeAdapter; + if (boundingBoxTypeAdapter == null) { + boundingBoxTypeAdapter = gson.getAdapter(BoundingBox.class); + this.boundingBoxTypeAdapter = boundingBoxTypeAdapter; } - bbox = boundingBox_adapter.read(jsonReader); + bbox = boundingBoxTypeAdapter.read(jsonReader); break; - } - case "geometries": { - TypeAdapter> list__geometry_adapter = this.list__geometry_adapter; - if (list__geometry_adapter == null) { - this.list__geometry_adapter = list__geometry_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Geometry.class)); + + case "geometries": + TypeAdapter> listGeometryAdapter = this.listGeometryAdapter; + if (listGeometryAdapter == null) { + TypeToken typeToken = TypeToken.getParameterized(List.class, Geometry.class); + listGeometryAdapter = + (TypeAdapter>) gson.getAdapter(typeToken); + this.listGeometryAdapter = listGeometryAdapter; } - geometries = list__geometry_adapter.read(jsonReader); + geometries = listGeometryAdapter.read(jsonReader); break; - } - default: { + + default: jsonReader.skipValue(); - } + } } jsonReader.endObject(); diff --git a/services-geojson/src/main/java/com/mapbox/geojson/LineString.java b/services-geojson/src/main/java/com/mapbox/geojson/LineString.java index 38c2466f4..f657610bb 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/LineString.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/LineString.java @@ -5,15 +5,9 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; -import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; -import com.mapbox.geojson.gson.BoundingBoxDeserializer; -import com.mapbox.geojson.gson.BoundingBoxSerializer; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; -import com.mapbox.geojson.gson.PointDeserializer; -import com.mapbox.geojson.gson.PointSerializer; import com.mapbox.geojson.utils.PolylineUtils; import java.io.IOException; @@ -79,8 +73,6 @@ public final class LineString implements CoordinateContainer>, Seria public static LineString fromJson(String json) { GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); - gson.registerTypeAdapter(Point.class, new PointDeserializer()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); return gson.create().fromJson(json, LineString.class); } @@ -238,8 +230,7 @@ public List coordinates() { @Override public String toJson() { GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapter(Point.class, new PointSerializer()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()); + gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); return gson.create().toJson(this); } @@ -277,12 +268,12 @@ public String toString() { } @Override - public boolean equals(Object o) { - if (o == this) { + public boolean equals(Object obj) { + if (obj == this) { return true; } - if (o instanceof LineString) { - LineString that = (LineString) o; + if (obj instanceof LineString) { + LineString that = (LineString) obj; return (this.type.equals(that.type())) && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) && (this.coordinates.equals(that.coordinates())); @@ -292,112 +283,41 @@ public boolean equals(Object o) { @Override public int hashCode() { - int h$ = 1; - h$ *= 1000003; - h$ ^= type.hashCode(); - h$ *= 1000003; - h$ ^= (bbox == null) ? 0 : bbox.hashCode(); - h$ *= 1000003; - h$ ^= coordinates.hashCode(); - return h$; + int hashCode = 1; + hashCode *= 1000003; + hashCode ^= type.hashCode(); + hashCode *= 1000003; + hashCode ^= (bbox == null) ? 0 : bbox.hashCode(); + hashCode *= 1000003; + hashCode ^= coordinates.hashCode(); + return hashCode; } - public static final class GsonTypeAdapter extends TypeAdapter { - private volatile TypeAdapter string_adapter; - private volatile TypeAdapter boundingBox_adapter; - private volatile TypeAdapter> list__point_adapter; - private final Gson gson; - public GsonTypeAdapter(Gson gson) { - this.gson = gson; + /** + * TypeAdapter for LineString geometry. + * + * @since 4.6.0 + */ + static final class GsonTypeAdapter extends BaseGeometryTypeAdapter> { + + GsonTypeAdapter(Gson gson) { + super(gson, new ListOfPointCoordinatesTypeAdapter()); } + @Override - @SuppressWarnings("unchecked") public void write(JsonWriter jsonWriter, LineString object) throws IOException { - if (object == null) { - jsonWriter.nullValue(); - return; - } - jsonWriter.beginObject(); - jsonWriter.name("type"); - if (object.type() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); - } - string_adapter.write(jsonWriter, object.type()); - } - jsonWriter.name("bbox"); - if (object.bbox() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); - } - boundingBox_adapter.write(jsonWriter, object.bbox()); - } - jsonWriter.name("coordinates"); - if (object.coordinates() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter> list__point_adapter = this.list__point_adapter; - if (list__point_adapter == null) { - this.list__point_adapter = list__point_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Point.class)); - } - list__point_adapter.write(jsonWriter, object.coordinates()); - } - jsonWriter.endObject(); + writeCoordinateContainer(jsonWriter, object); } + @Override - @SuppressWarnings("unchecked") public LineString read(JsonReader jsonReader) throws IOException { - if (jsonReader.peek() == JsonToken.NULL) { - jsonReader.nextNull(); - return null; - } - jsonReader.beginObject(); - String type = null; - BoundingBox bbox = null; - List coordinates = null; - while (jsonReader.hasNext()) { - String _name = jsonReader.nextName(); - if (jsonReader.peek() == JsonToken.NULL) { - jsonReader.nextNull(); - continue; - } - switch (_name) { - case "type": { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); - } - type = string_adapter.read(jsonReader); - break; - } - case "bbox": { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); - } - bbox = boundingBox_adapter.read(jsonReader); - break; - } - case "coordinates": { - TypeAdapter> list__point_adapter = this.list__point_adapter; - if (list__point_adapter == null) { - this.list__point_adapter = list__point_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Point.class)); - } - coordinates = list__point_adapter.read(jsonReader); - break; - } - default: { - jsonReader.skipValue(); - } - } - } - jsonReader.endObject(); + return (LineString) readCoordinateContainer(jsonReader); + } + + @Override + CoordinateContainer> createCoordinateContainer(String type, + BoundingBox bbox, + List coordinates) { return new LineString(type == null ? "LineString" : type, bbox, coordinates); } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/ListOfDoublesCoordinatesTypeAdapter.java b/services-geojson/src/main/java/com/mapbox/geojson/ListOfDoublesCoordinatesTypeAdapter.java new file mode 100644 index 000000000..a5480aee4 --- /dev/null +++ b/services-geojson/src/main/java/com/mapbox/geojson/ListOfDoublesCoordinatesTypeAdapter.java @@ -0,0 +1,25 @@ +package com.mapbox.geojson; + +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.util.List; + +/** + * Type Adapter to serialize/deserialize Poinr into/from for double array. + * + * @since 4.6.0 + */ +class ListOfDoublesCoordinatesTypeAdapter extends BaseCoordinatesTypeAdapter> { + + @Override + public void write(JsonWriter out, List value) throws IOException { + writePointList(out, value); + } + + @Override + public List read(JsonReader in) throws IOException { + return readPointList(in); + } +} diff --git a/services-geojson/src/main/java/com/mapbox/geojson/ListOfListOfPointCoordinatesTypeAdapter.java b/services-geojson/src/main/java/com/mapbox/geojson/ListOfListOfPointCoordinatesTypeAdapter.java new file mode 100644 index 000000000..e41f04026 --- /dev/null +++ b/services-geojson/src/main/java/com/mapbox/geojson/ListOfListOfPointCoordinatesTypeAdapter.java @@ -0,0 +1,74 @@ +package com.mapbox.geojson; + +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.mapbox.geojson.exception.GeoJsonException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Type Adapter to serialize/deserialize ist <List<Point>> + * into/from three dimentional double array. + * + * @since 4.6.0 + */ +class ListOfListOfPointCoordinatesTypeAdapter + extends BaseCoordinatesTypeAdapter>> { + + @Override + public void write(JsonWriter out, List> points) throws IOException { + + if (points == null) { + out.nullValue(); + return; + } + + out.beginArray(); + + for (List listOfPoints : points) { + + out.beginArray(); + + for (Point point : listOfPoints) { + writePoint(out, point); + } + out.endArray(); + } + + out.endArray(); + } + + @Override + public List> read(JsonReader in) throws IOException { + + if (in.peek() == JsonToken.NULL) { + throw new NullPointerException(); + } + + if (in.peek() == JsonToken.BEGIN_ARRAY) { + + in.beginArray(); + List> points = new ArrayList<>(); + + while (in.peek() == JsonToken.BEGIN_ARRAY) { + + in.beginArray(); + List listOfPoints = new ArrayList<>(); + + while (in.peek() == JsonToken.BEGIN_ARRAY) { + listOfPoints.add(readPoint(in)); + } + in.endArray(); + points.add(listOfPoints); + } + in.endArray(); + + return points; + } + + throw new GeoJsonException("coordinates should be array of array of array of double"); + } +} diff --git a/services-geojson/src/main/java/com/mapbox/geojson/ListOfPointCoordinatesTypeAdapter.java b/services-geojson/src/main/java/com/mapbox/geojson/ListOfPointCoordinatesTypeAdapter.java new file mode 100644 index 000000000..1ede3b278 --- /dev/null +++ b/services-geojson/src/main/java/com/mapbox/geojson/ListOfPointCoordinatesTypeAdapter.java @@ -0,0 +1,57 @@ +package com.mapbox.geojson; + +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.mapbox.geojson.exception.GeoJsonException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Type Adapter to serialize/deserialize List<Point> into/from two dimentional double array. + * + * @since 4.6.0 + */ +class ListOfPointCoordinatesTypeAdapter extends BaseCoordinatesTypeAdapter> { + + @Override + public void write(JsonWriter out, List points) throws IOException { + + if (points == null) { + out.nullValue(); + return; + } + + out.beginArray(); + + for (Point point : points) { + writePoint(out, point); + } + + out.endArray(); + } + + @Override + public List read(JsonReader in) throws IOException { + + if (in.peek() == JsonToken.NULL) { + throw new NullPointerException(); + } + + if (in.peek() == JsonToken.BEGIN_ARRAY) { + List points = new ArrayList<>(); + in.beginArray(); + + while (in.peek() == JsonToken.BEGIN_ARRAY) { + points.add(readPoint(in)); + } + in.endArray(); + + return points; + } + + throw new GeoJsonException("coordinates should be non-null array of array of double"); + } +} diff --git a/services-geojson/src/main/java/com/mapbox/geojson/ListofListofListOfPointCoordinatesTypeAdapter.java b/services-geojson/src/main/java/com/mapbox/geojson/ListofListofListOfPointCoordinatesTypeAdapter.java new file mode 100644 index 000000000..e71694914 --- /dev/null +++ b/services-geojson/src/main/java/com/mapbox/geojson/ListofListofListOfPointCoordinatesTypeAdapter.java @@ -0,0 +1,86 @@ +package com.mapbox.geojson; + +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.mapbox.geojson.exception.GeoJsonException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Type Adapter to serialize/deserialize List<List<List<Point>>> into/from + * four dimentional double array. + * + * @since 4.6.0 + */ +class ListofListofListOfPointCoordinatesTypeAdapter + extends BaseCoordinatesTypeAdapter>>> { + + @Override + public void write(JsonWriter out, List>> points) throws IOException { + + if (points == null) { + out.nullValue(); + return; + } + + out.beginArray(); + + for (List> listOfListOfPoints : points) { + + out.beginArray(); + + for (List listOfPoints : listOfListOfPoints) { + + out.beginArray(); + + for (Point point : listOfPoints) { + writePoint(out, point); + } + out.endArray(); + } + + out.endArray(); + } + out.endArray(); + } + + @Override + public List>> read(JsonReader in) throws IOException { + + if (in.peek() == JsonToken.NULL) { + throw new NullPointerException(); + } + + if (in.peek() == JsonToken.BEGIN_ARRAY) { + + in.beginArray(); + List>> listOfListOflistOfPoints = new ArrayList<>(); + while (in.peek() == JsonToken.BEGIN_ARRAY) { + + in.beginArray(); + List> listOfListOfPoints = new ArrayList<>(); + + while (in.peek() == JsonToken.BEGIN_ARRAY) { + + in.beginArray(); + List listOfPoints = new ArrayList<>(); + while (in.peek() == JsonToken.BEGIN_ARRAY) { + listOfPoints.add(readPoint(in)); + } + in.endArray(); + + listOfListOfPoints.add(listOfPoints); + } + in.endArray(); + listOfListOflistOfPoints.add(listOfListOfPoints); + } + in.endArray(); + return listOfListOflistOfPoints; + } + + throw new GeoJsonException("coordinates should be array of array of array of double"); + } +} diff --git a/services-geojson/src/main/java/com/mapbox/geojson/MultiLineString.java b/services-geojson/src/main/java/com/mapbox/geojson/MultiLineString.java index e05475941..286eaff69 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/MultiLineString.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/MultiLineString.java @@ -5,15 +5,9 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; -import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; -import com.mapbox.geojson.gson.BoundingBoxDeserializer; -import com.mapbox.geojson.gson.BoundingBoxSerializer; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; -import com.mapbox.geojson.gson.PointDeserializer; -import com.mapbox.geojson.gson.PointSerializer; import java.io.IOException; import java.io.Serializable; @@ -79,8 +73,6 @@ public final class MultiLineString public static MultiLineString fromJson(@NonNull String json) { GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); - gson.registerTypeAdapter(Point.class, new PointDeserializer()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); return gson.create().fromJson(json, MultiLineString.class); } @@ -277,8 +269,7 @@ public List lineStrings() { @Override public String toJson() { GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapter(Point.class, new PointSerializer()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()); + gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); return gson.create().toJson(this); } @@ -303,12 +294,12 @@ public String toString() { } @Override - public boolean equals(Object o) { - if (o == this) { + public boolean equals(Object obj) { + if (obj == this) { return true; } - if (o instanceof MultiLineString) { - MultiLineString that = (MultiLineString) o; + if (obj instanceof MultiLineString) { + MultiLineString that = (MultiLineString) obj; return (this.type.equals(that.type())) && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) && (this.coordinates.equals(that.coordinates())); @@ -318,113 +309,43 @@ public boolean equals(Object o) { @Override public int hashCode() { - int h$ = 1; - h$ *= 1000003; - h$ ^= type.hashCode(); - h$ *= 1000003; - h$ ^= (bbox == null) ? 0 : bbox.hashCode(); - h$ *= 1000003; - h$ ^= coordinates.hashCode(); - return h$; + int hashCode = 1; + hashCode *= 1000003; + hashCode ^= type.hashCode(); + hashCode *= 1000003; + hashCode ^= (bbox == null) ? 0 : bbox.hashCode(); + hashCode *= 1000003; + hashCode ^= coordinates.hashCode(); + return hashCode; } - public static final class GsonTypeAdapter extends TypeAdapter { - private volatile TypeAdapter string_adapter; - private volatile TypeAdapter boundingBox_adapter; - private volatile TypeAdapter>> list__list__point_adapter; - private final Gson gson; - public GsonTypeAdapter(Gson gson) { - this.gson = gson; + /** + * TypeAdapter for MultiLineString geometry. + * + * @since 4.6.0 + */ + static final class GsonTypeAdapter + extends BaseGeometryTypeAdapter>> { + + GsonTypeAdapter(Gson gson) { + super(gson, new ListOfListOfPointCoordinatesTypeAdapter()); } + @Override - @SuppressWarnings("unchecked") public void write(JsonWriter jsonWriter, MultiLineString object) throws IOException { - if (object == null) { - jsonWriter.nullValue(); - return; - } - jsonWriter.beginObject(); - jsonWriter.name("type"); - if (object.type() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); - } - string_adapter.write(jsonWriter, object.type()); - } - jsonWriter.name("bbox"); - if (object.bbox() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); - } - boundingBox_adapter.write(jsonWriter, object.bbox()); - } - jsonWriter.name("coordinates"); - if (object.coordinates() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter>> list__list__point_adapter = this.list__list__point_adapter; - if (list__list__point_adapter == null) { - this.list__list__point_adapter = list__list__point_adapter = (TypeAdapter>>) gson.getAdapter(TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, Point.class).getType())); - } - list__list__point_adapter.write(jsonWriter, object.coordinates()); - } - jsonWriter.endObject(); + writeCoordinateContainer(jsonWriter, object); } + @Override - @SuppressWarnings("unchecked") public MultiLineString read(JsonReader jsonReader) throws IOException { - if (jsonReader.peek() == JsonToken.NULL) { - jsonReader.nextNull(); - return null; - } - jsonReader.beginObject(); - String type = null; - BoundingBox bbox = null; - List> coordinates = null; - while (jsonReader.hasNext()) { - String _name = jsonReader.nextName(); - if (jsonReader.peek() == JsonToken.NULL) { - jsonReader.nextNull(); - continue; - } - switch (_name) { - case "type": { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); - } - type = string_adapter.read(jsonReader); - break; - } - case "bbox": { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); - } - bbox = boundingBox_adapter.read(jsonReader); - break; - } - case "coordinates": { - TypeAdapter>> list__list__point_adapter = this.list__list__point_adapter; - if (list__list__point_adapter == null) { - this.list__list__point_adapter = list__list__point_adapter = (TypeAdapter>>) gson.getAdapter(TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, Point.class).getType())); - } - coordinates = list__list__point_adapter.read(jsonReader); - break; - } - default: { - jsonReader.skipValue(); - } - } - } - jsonReader.endObject(); - return new MultiLineString(type, bbox, coordinates); + return (MultiLineString) readCoordinateContainer(jsonReader); + } + + @Override + CoordinateContainer>> createCoordinateContainer(String type, + BoundingBox bbox, + List> coords) { + return new MultiLineString(type == null ? "MultiLineString" : type, bbox, coords); } } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/MultiPoint.java b/services-geojson/src/main/java/com/mapbox/geojson/MultiPoint.java index a3c754ec0..d166eb9fd 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/MultiPoint.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/MultiPoint.java @@ -5,15 +5,9 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; -import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; -import com.mapbox.geojson.gson.BoundingBoxDeserializer; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; -import com.mapbox.geojson.gson.PointDeserializer; -import com.mapbox.geojson.gson.BoundingBoxSerializer; -import com.mapbox.geojson.gson.PointSerializer; import java.io.IOException; import java.io.Serializable; @@ -64,8 +58,6 @@ public final class MultiPoint implements CoordinateContainer>, Seria public static MultiPoint fromJson(@NonNull String json) { GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); - gson.registerTypeAdapter(Point.class, new PointDeserializer()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); return gson.create().fromJson(json, MultiPoint.class); } @@ -147,7 +139,9 @@ public String type() { */ @Nullable @Override - public BoundingBox bbox() { return bbox; } + public BoundingBox bbox() { + return bbox; + } /** * provides the list of {@link Point}s that make up the MultiPoint geometry. @@ -171,8 +165,7 @@ public List coordinates() { @Override public String toJson() { GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapter(Point.class, new PointSerializer()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()); + gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); return gson.create().toJson(this); } @@ -197,12 +190,12 @@ public String toString() { } @Override - public boolean equals(Object o) { - if (o == this) { + public boolean equals(Object obj) { + if (obj == this) { return true; } - if (o instanceof MultiPoint) { - MultiPoint that = (MultiPoint) o; + if (obj instanceof MultiPoint) { + MultiPoint that = (MultiPoint) obj; return (this.type.equals(that.type())) && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) && (this.coordinates.equals(that.coordinates())); @@ -212,113 +205,42 @@ public boolean equals(Object o) { @Override public int hashCode() { - int h$ = 1; - h$ *= 1000003; - h$ ^= type.hashCode(); - h$ *= 1000003; - h$ ^= (bbox == null) ? 0 : bbox.hashCode(); - h$ *= 1000003; - h$ ^= coordinates.hashCode(); - return h$; + int hashCode = 1; + hashCode *= 1000003; + hashCode ^= type.hashCode(); + hashCode *= 1000003; + hashCode ^= (bbox == null) ? 0 : bbox.hashCode(); + hashCode *= 1000003; + hashCode ^= coordinates.hashCode(); + return hashCode; } - public static final class GsonTypeAdapter extends TypeAdapter { - private volatile TypeAdapter string_adapter; - private volatile TypeAdapter boundingBox_adapter; - private volatile TypeAdapter> list__point_adapter; - private final Gson gson; - public GsonTypeAdapter(Gson gson) { - this.gson = gson; + /** + * TypeAdapter for MultiPoint geometry. + * + * @since 4.6.0 + */ + static final class GsonTypeAdapter extends BaseGeometryTypeAdapter> { + + GsonTypeAdapter(Gson gson) { + super(gson, new ListOfPointCoordinatesTypeAdapter()); } + @Override - @SuppressWarnings("unchecked") public void write(JsonWriter jsonWriter, MultiPoint object) throws IOException { - if (object == null) { - jsonWriter.nullValue(); - return; - } - jsonWriter.beginObject(); - jsonWriter.name("type"); - if (object.type() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); - } - string_adapter.write(jsonWriter, object.type()); - } - jsonWriter.name("bbox"); - if (object.bbox() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); - } - boundingBox_adapter.write(jsonWriter, object.bbox()); - } - jsonWriter.name("coordinates"); - if (object.coordinates() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter> list__point_adapter = this.list__point_adapter; - if (list__point_adapter == null) { - this.list__point_adapter = list__point_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Point.class)); - } - list__point_adapter.write(jsonWriter, object.coordinates()); - } - jsonWriter.endObject(); + writeCoordinateContainer(jsonWriter, object); } + @Override - @SuppressWarnings("unchecked") public MultiPoint read(JsonReader jsonReader) throws IOException { - if (jsonReader.peek() == JsonToken.NULL) { - jsonReader.nextNull(); - return null; - } - jsonReader.beginObject(); - String type = null; - BoundingBox bbox = null; - List coordinates = null; - while (jsonReader.hasNext()) { - String _name = jsonReader.nextName(); - if (jsonReader.peek() == JsonToken.NULL) { - jsonReader.nextNull(); - continue; - } - switch (_name) { - case "type": { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); - } - type = string_adapter.read(jsonReader); - break; - } - case "bbox": { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); - } - bbox = boundingBox_adapter.read(jsonReader); - break; - } - case "coordinates": { - TypeAdapter> list__point_adapter = this.list__point_adapter; - if (list__point_adapter == null) { - this.list__point_adapter = list__point_adapter = (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Point.class)); - } - coordinates = list__point_adapter.read(jsonReader); - break; - } - default: { - jsonReader.skipValue(); - } - } - } - jsonReader.endObject(); - return new MultiPoint(type, bbox, coordinates); + return (MultiPoint) readCoordinateContainer(jsonReader); + } + + @Override + CoordinateContainer> createCoordinateContainer(String type, + BoundingBox bbox, + List coordinates) { + return new MultiPoint(type == null ? "MultiPoint" : type, bbox, coordinates); } } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/MultiPolygon.java b/services-geojson/src/main/java/com/mapbox/geojson/MultiPolygon.java index 95ae5cb76..1e8701c70 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/MultiPolygon.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/MultiPolygon.java @@ -5,15 +5,9 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; -import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; -import com.mapbox.geojson.gson.BoundingBoxDeserializer; -import com.mapbox.geojson.gson.BoundingBoxSerializer; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; -import com.mapbox.geojson.gson.PointDeserializer; -import com.mapbox.geojson.gson.PointSerializer; import java.io.IOException; import java.io.Serializable; @@ -97,8 +91,6 @@ public final class MultiPolygon public static MultiPolygon fromJson(String json) { GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); - gson.registerTypeAdapter(Point.class, new PointDeserializer()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); return gson.create().fromJson(json, MultiPolygon.class); } @@ -296,8 +288,7 @@ public List>> coordinates() { @Override public String toJson() { GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapter(Point.class, new PointSerializer()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()); + gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); return gson.create().toJson(this); } @@ -322,12 +313,12 @@ public String toString() { } @Override - public boolean equals(Object o) { - if (o == this) { + public boolean equals(Object obj) { + if (obj == this) { return true; } - if (o instanceof MultiPolygon) { - MultiPolygon that = (MultiPolygon) o; + if (obj instanceof MultiPolygon) { + MultiPolygon that = (MultiPolygon) obj; return (this.type.equals(that.type())) && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) && (this.coordinates.equals(that.coordinates())); @@ -337,113 +328,42 @@ public boolean equals(Object o) { @Override public int hashCode() { - int h$ = 1; - h$ *= 1000003; - h$ ^= type.hashCode(); - h$ *= 1000003; - h$ ^= (bbox == null) ? 0 : bbox.hashCode(); - h$ *= 1000003; - h$ ^= coordinates.hashCode(); - return h$; + int hashCode = 1; + hashCode *= 1000003; + hashCode ^= type.hashCode(); + hashCode *= 1000003; + hashCode ^= (bbox == null) ? 0 : bbox.hashCode(); + hashCode *= 1000003; + hashCode ^= coordinates.hashCode(); + return hashCode; } - public static final class GsonTypeAdapter extends TypeAdapter { - private volatile TypeAdapter string_adapter; - private volatile TypeAdapter boundingBox_adapter; - private volatile TypeAdapter>>> list__list__list__point_adapter; - private final Gson gson; - public GsonTypeAdapter(Gson gson) { - this.gson = gson; + /** + * TypeAdapter for MultiPolygon geometry. + * + * @since 4.6.0 + */ + static final class GsonTypeAdapter + extends BaseGeometryTypeAdapter>>> { + + GsonTypeAdapter(Gson gson) { + super(gson, new ListofListofListOfPointCoordinatesTypeAdapter()); } + @Override - @SuppressWarnings("unchecked") public void write(JsonWriter jsonWriter, MultiPolygon object) throws IOException { - if (object == null) { - jsonWriter.nullValue(); - return; - } - jsonWriter.beginObject(); - jsonWriter.name("type"); - if (object.type() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); - } - string_adapter.write(jsonWriter, object.type()); - } - jsonWriter.name("bbox"); - if (object.bbox() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); - } - boundingBox_adapter.write(jsonWriter, object.bbox()); - } - jsonWriter.name("coordinates"); - if (object.coordinates() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter>>> list__list__list__point_adapter = this.list__list__list__point_adapter; - if (list__list__list__point_adapter == null) { - this.list__list__list__point_adapter = list__list__list__point_adapter = (TypeAdapter>>>) gson.getAdapter(TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, Point.class).getType()).getType())); - } - list__list__list__point_adapter.write(jsonWriter, object.coordinates()); - } - jsonWriter.endObject(); + writeCoordinateContainer(jsonWriter, object); } + @Override - @SuppressWarnings("unchecked") public MultiPolygon read(JsonReader jsonReader) throws IOException { - if (jsonReader.peek() == JsonToken.NULL) { - jsonReader.nextNull(); - return null; - } - jsonReader.beginObject(); - String type = null; - BoundingBox bbox = null; - List>> coordinates = null; - while (jsonReader.hasNext()) { - String _name = jsonReader.nextName(); - if (jsonReader.peek() == JsonToken.NULL) { - jsonReader.nextNull(); - continue; - } - switch (_name) { - case "type": { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); - } - type = string_adapter.read(jsonReader); - break; - } - case "bbox": { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); - } - bbox = boundingBox_adapter.read(jsonReader); - break; - } - case "coordinates": { - TypeAdapter>>> list__list__list__point_adapter = this.list__list__list__point_adapter; - if (list__list__list__point_adapter == null) { - this.list__list__list__point_adapter = list__list__list__point_adapter = (TypeAdapter>>>) gson.getAdapter(TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, Point.class).getType()).getType())); - } - coordinates = list__list__list__point_adapter.read(jsonReader); - break; - } - default: { - jsonReader.skipValue(); - } - } - } - jsonReader.endObject(); - return new MultiPolygon(type, bbox, coordinates); + return (MultiPolygon) readCoordinateContainer(jsonReader); + } + + @Override + CoordinateContainer>>> + createCoordinateContainer(String type, BoundingBox bbox, List>> coords) { + return new MultiPolygon(type == null ? "MultiPolygon" : type, bbox, coords); } } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/Point.java b/services-geojson/src/main/java/com/mapbox/geojson/Point.java index cb2eaf4e1..0e0837a17 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/Point.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/Point.java @@ -11,17 +11,9 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; -import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; -import com.mapbox.geojson.gson.BoundingBoxDeserializer; -import com.mapbox.geojson.gson.BoundingBoxSerializer; -import com.mapbox.geojson.gson.CoordinateTypeAdapter; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; -import com.mapbox.geojson.gson.GeometryTypeAdapter; -import com.mapbox.geojson.gson.PointDeserializer; -import com.mapbox.geojson.gson.PointSerializer; import com.mapbox.geojson.shifter.CoordinateShifterManager; import java.io.IOException; @@ -63,10 +55,13 @@ public final class Point implements CoordinateContainer>, Serializa private static final String TYPE = "Point"; + @NonNull private final String type; + @Nullable private final BoundingBox bbox; + @NonNull private final List coordinates; /** @@ -84,10 +79,7 @@ public final class Point implements CoordinateContainer>, Serializa */ public static Point fromJson(@NonNull String json) { GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapter(Point.class, new PointDeserializer()); - gson.registerTypeAdapter(new TypeToken>(){}.getType(), - new CoordinateTypeAdapter()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); + gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); return gson.create().fromJson(json, Point.class); } @@ -208,7 +200,7 @@ static Point fromLngLat(@NonNull double[] coords) { } this.type = type; this.bbox = bbox; - if (coordinates == null) { + if (coordinates == null || coordinates.size() == 0) { throw new NullPointerException("Null coordinates"); } this.coordinates = coordinates; @@ -322,10 +314,7 @@ public List coordinates() { @Override public String toJson() { GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapter(Geometry.class, new GeometryTypeAdapter()); - gson.registerTypeAdapter(new TypeToken>(){}.getType(), - new CoordinateTypeAdapter()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()); + gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); return gson.create().toJson(this); } @@ -342,21 +331,20 @@ public static TypeAdapter typeAdapter(Gson gson) { @Override public String toString() { -// return "Point{" -// + "type=" + type + ", " -// + "bbox=" + bbox + ", " -// + "coordinates=" + coordinates -// + "}"; - return "" + coordinates; + return "Point{" + + "type=" + type + ", " + + "bbox=" + bbox + ", " + + "coordinates=" + coordinates + + "}"; } @Override - public boolean equals(Object o) { - if (o == this) { + public boolean equals(Object obj) { + if (obj == this) { return true; } - if (o instanceof Point) { - Point that = (Point) o; + if (obj instanceof Point) { + Point that = (Point) obj; return (this.type.equals(that.type())) && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) && (this.coordinates.equals(that.coordinates())); @@ -366,114 +354,43 @@ public boolean equals(Object o) { @Override public int hashCode() { - int h$ = 1; - h$ *= 1000003; - h$ ^= type.hashCode(); - h$ *= 1000003; - h$ ^= (bbox == null) ? 0 : bbox.hashCode(); - h$ *= 1000003; - h$ ^= coordinates.hashCode(); - return h$; + int hashCode = 1; + hashCode *= 1000003; + hashCode ^= type.hashCode(); + hashCode *= 1000003; + hashCode ^= (bbox == null) ? 0 : bbox.hashCode(); + hashCode *= 1000003; + hashCode ^= coordinates.hashCode(); + return hashCode; } - public static final class GsonTypeAdapter extends TypeAdapter { - private volatile TypeAdapter string_adapter; - private volatile TypeAdapter boundingBox_adapter; - private volatile TypeAdapter> list__double_adapter; - private final Gson gson; - public GsonTypeAdapter(Gson gson) { - this.gson = gson; + /** + * TypeAdapter for Point geometry. + * + * @since 4.6.0 + */ + static final class GsonTypeAdapter extends BaseGeometryTypeAdapter> { + + GsonTypeAdapter(Gson gson) { + super(gson, new ListOfDoublesCoordinatesTypeAdapter()); } + @Override @SuppressWarnings("unchecked") public void write(JsonWriter jsonWriter, Point object) throws IOException { - if (object == null) { - jsonWriter.nullValue(); - return; - } - jsonWriter.beginObject(); - jsonWriter.name("type"); - if (object.type() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); - } - string_adapter.write(jsonWriter, object.type()); - } - jsonWriter.name("bbox"); - if (object.bbox() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); - } - boundingBox_adapter.write(jsonWriter, object.bbox()); - } - jsonWriter.name("coordinates"); - if (object.coordinates() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter> list__double_adapter = this.list__double_adapter; - if (list__double_adapter == null) { - this.list__double_adapter = list__double_adapter = - (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Double.class)); - } - list__double_adapter.write(jsonWriter, object.coordinates()); - } - jsonWriter.endObject(); + writeCoordinateContainer(jsonWriter, object); } + @Override @SuppressWarnings("unchecked") public Point read(JsonReader jsonReader) throws IOException { - if (jsonReader.peek() == JsonToken.NULL) { - jsonReader.nextNull(); - return null; - } - jsonReader.beginObject(); - String type = null; - BoundingBox bbox = null; - List coordinates = null; - while (jsonReader.hasNext()) { - String _name = jsonReader.nextName(); - if (jsonReader.peek() == JsonToken.NULL) { - jsonReader.nextNull(); - continue; - } - switch (_name) { - case "type": { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); - } - type = string_adapter.read(jsonReader); - break; - } - case "bbox": { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); - } - bbox = boundingBox_adapter.read(jsonReader); - break; - } - case "coordinates": { - TypeAdapter> list__double_adapter = this.list__double_adapter; - if (list__double_adapter == null) { - this.list__double_adapter = list__double_adapter = - (TypeAdapter>) gson.getAdapter(TypeToken.getParameterized(List.class, Double.class)); - } - coordinates = list__double_adapter.read(jsonReader); - break; - } - default: { - jsonReader.skipValue(); - } - } - } - jsonReader.endObject(); + return (Point)readCoordinateContainer(jsonReader); + } + + @Override + CoordinateContainer> createCoordinateContainer(String type, + BoundingBox bbox, + List coordinates) { return new Point(type == null ? "Point" : type, bbox, coordinates); } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/PointAsCoordinatesTypeAdapter.java b/services-geojson/src/main/java/com/mapbox/geojson/PointAsCoordinatesTypeAdapter.java new file mode 100644 index 000000000..1b5d539bf --- /dev/null +++ b/services-geojson/src/main/java/com/mapbox/geojson/PointAsCoordinatesTypeAdapter.java @@ -0,0 +1,25 @@ +package com.mapbox.geojson; + +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; + +/** + * TypeAdapter to serialize Point as coordinates, i.e array of doubles and + * to deserialize into Point out of array of doubles. + * + * @since 4.6.0 + */ +public class PointAsCoordinatesTypeAdapter extends BaseCoordinatesTypeAdapter { + + @Override + public void write(JsonWriter out, Point value) throws IOException { + writePoint(out, value); + } + + @Override + public Point read(JsonReader in) throws IOException { + return readPoint(in); + } +} diff --git a/services-geojson/src/main/java/com/mapbox/geojson/Polygon.java b/services-geojson/src/main/java/com/mapbox/geojson/Polygon.java index 580b1f484..9545abe66 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/Polygon.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/Polygon.java @@ -7,17 +7,10 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; -import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; -import com.mapbox.geojson.gson.GeoJsonAdapterFactory; import com.mapbox.geojson.exception.GeoJsonException; -import com.mapbox.geojson.gson.BoundingBoxDeserializer; -import com.mapbox.geojson.gson.GeometryDeserializer; -import com.mapbox.geojson.gson.PointDeserializer; -import com.mapbox.geojson.gson.BoundingBoxSerializer; -import com.mapbox.geojson.gson.PointSerializer; +import com.mapbox.geojson.gson.GeoJsonAdapterFactory; import java.io.IOException; import java.io.Serializable; @@ -87,8 +80,6 @@ public final class Polygon implements CoordinateContainer>>, Se public static Polygon fromJson(@NonNull String json) { GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); - gson.registerTypeAdapter(Point.class, new PointDeserializer()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); return gson.create().fromJson(json, Polygon.class); } @@ -363,8 +354,7 @@ public List> coordinates() { @Override public String toJson() { GsonBuilder gson = new GsonBuilder(); - gson.registerTypeAdapter(Point.class, new PointSerializer()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxSerializer()); + gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); return gson.create().toJson(this); } @@ -411,12 +401,12 @@ public String toString() { } @Override - public boolean equals(Object o) { - if (o == this) { + public boolean equals(Object obj) { + if (obj == this) { return true; } - if (o instanceof Polygon) { - Polygon that = (Polygon) o; + if (obj instanceof Polygon) { + Polygon that = (Polygon) obj; return (this.type.equals(that.type())) && ((this.bbox == null) ? (that.bbox() == null) : this.bbox.equals(that.bbox())) && (this.coordinates.equals(that.coordinates())); @@ -426,113 +416,42 @@ public boolean equals(Object o) { @Override public int hashCode() { - int h$ = 1; - h$ *= 1000003; - h$ ^= type.hashCode(); - h$ *= 1000003; - h$ ^= (bbox == null) ? 0 : bbox.hashCode(); - h$ *= 1000003; - h$ ^= coordinates.hashCode(); - return h$; + int hashCode = 1; + hashCode *= 1000003; + hashCode ^= type.hashCode(); + hashCode *= 1000003; + hashCode ^= (bbox == null) ? 0 : bbox.hashCode(); + hashCode *= 1000003; + hashCode ^= coordinates.hashCode(); + return hashCode; } - public static final class GsonTypeAdapter extends TypeAdapter { - private volatile TypeAdapter string_adapter; - private volatile TypeAdapter boundingBox_adapter; - private volatile TypeAdapter>> list__list__point_adapter; - private final Gson gson; - public GsonTypeAdapter(Gson gson) { - this.gson = gson; + /** + * TypeAdapter for Polygon geometry. + * + * @since 4.6.0 + */ + static final class GsonTypeAdapter extends BaseGeometryTypeAdapter>> { + + GsonTypeAdapter(Gson gson) { + super(gson, new ListOfListOfPointCoordinatesTypeAdapter()); } + @Override - @SuppressWarnings("unchecked") public void write(JsonWriter jsonWriter, Polygon object) throws IOException { - if (object == null) { - jsonWriter.nullValue(); - return; - } - jsonWriter.beginObject(); - jsonWriter.name("type"); - if (object.type() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); - } - string_adapter.write(jsonWriter, object.type()); - } - jsonWriter.name("bbox"); - if (object.bbox() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); - } - boundingBox_adapter.write(jsonWriter, object.bbox()); - } - jsonWriter.name("coordinates"); - if (object.coordinates() == null) { - jsonWriter.nullValue(); - } else { - TypeAdapter>> list__list__point_adapter = this.list__list__point_adapter; - if (list__list__point_adapter == null) { - this.list__list__point_adapter = list__list__point_adapter = (TypeAdapter>>) gson.getAdapter(TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, Point.class).getType())); - } - list__list__point_adapter.write(jsonWriter, object.coordinates()); - } - jsonWriter.endObject(); + writeCoordinateContainer(jsonWriter, object); } + @Override - @SuppressWarnings("unchecked") public Polygon read(JsonReader jsonReader) throws IOException { - if (jsonReader.peek() == JsonToken.NULL) { - jsonReader.nextNull(); - return null; - } - jsonReader.beginObject(); - String type = null; - BoundingBox bbox = null; - List> coordinates = null; - while (jsonReader.hasNext()) { - String _name = jsonReader.nextName(); - if (jsonReader.peek() == JsonToken.NULL) { - jsonReader.nextNull(); - continue; - } - switch (_name) { - case "type": { - TypeAdapter string_adapter = this.string_adapter; - if (string_adapter == null) { - this.string_adapter = string_adapter = gson.getAdapter(String.class); - } - type = string_adapter.read(jsonReader); - break; - } - case "bbox": { - TypeAdapter boundingBox_adapter = this.boundingBox_adapter; - if (boundingBox_adapter == null) { - this.boundingBox_adapter = boundingBox_adapter = gson.getAdapter(BoundingBox.class); - } - bbox = boundingBox_adapter.read(jsonReader); - break; - } - case "coordinates": { - TypeAdapter>> list__list__point_adapter = this.list__list__point_adapter; - if (list__list__point_adapter == null) { - this.list__list__point_adapter = list__list__point_adapter = (TypeAdapter>>) gson.getAdapter(TypeToken.getParameterized(List.class, TypeToken.getParameterized(List.class, Point.class).getType())); - } - coordinates = list__list__point_adapter.read(jsonReader); - break; - } - default: { - jsonReader.skipValue(); - } - } - } - jsonReader.endObject(); - return new Polygon(type, bbox, coordinates); + return (Polygon) readCoordinateContainer(jsonReader); + } + + @Override + CoordinateContainer>> createCoordinateContainer(String type, + BoundingBox bbox, + List> coords) { + return new Polygon(type == null ? "Polygon" : type, bbox, coords); } } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/BoundingBoxDeserializer.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/BoundingBoxDeserializer.java index 40cd0ca62..c5a3c4b19 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/gson/BoundingBoxDeserializer.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/BoundingBoxDeserializer.java @@ -15,7 +15,10 @@ * {@link BoundingBox} object for easier consumption in developers java applications. * * @since 3.0.0 + * @deprecated this class is deprecated, {@link com.mapbox.geojson.gson.BoundingBoxTypeAdapter} + * should be used to serialize/deserialize coordinates as Points. */ +@Deprecated public class BoundingBoxDeserializer implements JsonDeserializer { /** diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/BoundingBoxSerializer.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/BoundingBoxSerializer.java index f347d358d..8de3b875a 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/gson/BoundingBoxSerializer.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/BoundingBoxSerializer.java @@ -18,7 +18,10 @@ * element which can be read by GSON and added to the final JSON output. * * @since 3.0.0 + * @deprecated this class is deprecated, {@link com.mapbox.geojson.gson.BoundingBoxTypeAdapter} + * should be used to serialize/deserialize coordinates as Points. */ +@Deprecated public class BoundingBoxSerializer implements JsonSerializer { /** diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/BoundingBoxTypeAdapter.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/BoundingBoxTypeAdapter.java new file mode 100644 index 000000000..9939c87db --- /dev/null +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/BoundingBoxTypeAdapter.java @@ -0,0 +1,90 @@ +package com.mapbox.geojson.gson; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import com.mapbox.geojson.BoundingBox; +import com.mapbox.geojson.Point; +import com.mapbox.geojson.exception.GeoJsonException; +import com.mapbox.geojson.shifter.CoordinateShifterManager; +import com.mapbox.geojson.utils.GeoJsonUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Adapter to read and write coordinates for BoundingBox class. + * + * @since 4.6.0 + */ +public class BoundingBoxTypeAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, BoundingBox value) throws IOException { + + if (value == null) { + out.nullValue(); + return; + } + + out.beginArray(); + + // Southwest + Point point = value.southwest(); + List unshiftedCoordinates = + CoordinateShifterManager.getCoordinateShifter().unshiftPoint(point); + + out.value(GeoJsonUtils.trim(unshiftedCoordinates.get(0))); + out.value(GeoJsonUtils.trim(unshiftedCoordinates.get(1))); + if (point.hasAltitude()) { + out.value(unshiftedCoordinates.get(2)); + } + + // Northeast + point = value.northeast(); + unshiftedCoordinates = + CoordinateShifterManager.getCoordinateShifter().unshiftPoint(point); + out.value(GeoJsonUtils.trim(unshiftedCoordinates.get(0))); + out.value(GeoJsonUtils.trim(unshiftedCoordinates.get(1))); + if (point.hasAltitude()) { + out.value(unshiftedCoordinates.get(2)); + } + + out.endArray(); + } + + @Override + public BoundingBox read(JsonReader in) throws IOException { + + List rawCoordinates = new ArrayList(); + in.beginArray(); + while (in.hasNext()) { + rawCoordinates.add(in.nextDouble()); + } + in.endArray(); + + if (rawCoordinates.size() == 6) { + return BoundingBox.fromLngLats( + rawCoordinates.get(0), + rawCoordinates.get(1), + rawCoordinates.get(2), + rawCoordinates.get(3), + rawCoordinates.get(4), + rawCoordinates.get(5)); + } + if (rawCoordinates.size() == 4) { + return BoundingBox.fromLngLats( + rawCoordinates.get(0), + rawCoordinates.get(1), + rawCoordinates.get(2), + rawCoordinates.get(3)); + } else { + throw new GeoJsonException("The value of the bbox member MUST be an array of length 2*n where" + + " n is the number of dimensions represented in the contained geometries," + + "with all axes of the most southwesterly point followed " + + " by all axes of the more northeasterly point. The " + + "axes order of a bbox follows the axes order of geometries."); + } + } +} diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/CoordinateTypeAdapter.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/CoordinateTypeAdapter.java index 91be6f720..052ad07e9 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/gson/CoordinateTypeAdapter.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/CoordinateTypeAdapter.java @@ -2,7 +2,6 @@ import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import com.mapbox.geojson.shifter.CoordinateShifterManager; import com.mapbox.geojson.utils.GeoJsonUtils; @@ -15,16 +14,14 @@ * Adapter to read and write coordinates for Point class. * * @since 4.1.0 + * @deprecated this class is deprecated, {@link com.mapbox.geojson.PointAsCoordinatesTypeAdapter} + * should be used to serialize/deserialize coordinates as Points. */ +@Deprecated public class CoordinateTypeAdapter extends TypeAdapter> { @Override public void write(JsonWriter out, List value) throws IOException { - if (value == null) { - out.nullValue(); - return; - } - out.beginArray(); // Unshift coordinates @@ -43,13 +40,6 @@ public void write(JsonWriter out, List value) throws IOException { @Override public List read(JsonReader in) throws IOException { - - if (in.peek() == JsonToken.NULL) { - //in.nextNull(); - //return null; - throw new NullPointerException(); - } - List coordinates = new ArrayList(); in.beginArray(); while (in.hasNext()) { diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeoJsonAdapterFactory.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeoJsonAdapterFactory.java index 39f34ffb5..6ce8a0e46 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeoJsonAdapterFactory.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeoJsonAdapterFactory.java @@ -4,11 +4,9 @@ import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapterFactory; import com.google.gson.reflect.TypeToken; -import com.google.gson.typeadapters.RuntimeTypeAdapterFactory; import com.mapbox.geojson.BoundingBox; import com.mapbox.geojson.Feature; import com.mapbox.geojson.FeatureCollection; -import com.mapbox.geojson.Geometry; import com.mapbox.geojson.GeometryCollection; import com.mapbox.geojson.LineString; import com.mapbox.geojson.MultiLineString; @@ -16,15 +14,13 @@ import com.mapbox.geojson.MultiPolygon; import com.mapbox.geojson.Point; import com.mapbox.geojson.Polygon; -import com.ryanharter.auto.value.gson.GsonTypeAdapterFactory; /** - * A GeoJson type adapter factory for convenience when using AutoValue and handling - * serialization/deserialization. The majority of this class gets generated during compilation time. + * A GeoJson type adapter factory for convenience for + * serialization/deserialization. * * @since 3.0.0 */ -@GsonTypeAdapterFactory public abstract class GeoJsonAdapterFactory implements TypeAdapterFactory { /** @@ -38,15 +34,19 @@ public static TypeAdapterFactory create() { return new GeoJsonAdapterFactoryIml(); } + /** + * GeoJsonAdapterFactory implementation. + * + * @since 3.0.0 + */ public static final class GeoJsonAdapterFactoryIml extends GeoJsonAdapterFactory { @Override @SuppressWarnings("unchecked") public TypeAdapter create(Gson gson, TypeToken type) { Class rawType = type.getRawType(); - /*if (BoundingBox.class.isAssignableFrom(rawType)) { + if (BoundingBox.class.isAssignableFrom(rawType)) { return (TypeAdapter) BoundingBox.typeAdapter(gson); - } else */ - if (Feature.class.isAssignableFrom(rawType)) { + } else if (Feature.class.isAssignableFrom(rawType)) { return (TypeAdapter) Feature.typeAdapter(gson); } else if (FeatureCollection.class.isAssignableFrom(rawType)) { return (TypeAdapter) FeatureCollection.typeAdapter(gson); @@ -62,6 +62,8 @@ public TypeAdapter create(Gson gson, TypeToken type) { return (TypeAdapter) MultiPolygon.typeAdapter(gson); } else if (Polygon.class.isAssignableFrom(rawType)) { return (TypeAdapter) Polygon.typeAdapter(gson); + } else if (Point.class.isAssignableFrom(rawType)) { + return (TypeAdapter) Point.typeAdapter(gson); } return null; } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryDeserializer.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryDeserializer.java index f376d3c72..7c4acdcbc 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryDeserializer.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryDeserializer.java @@ -13,7 +13,10 @@ * that Gson shows when trying to deserialize a list of {@link Geometry}. * * @since 1.0.0 + * @deprecated this class is deprecated, {@link com.mapbox.geojson.GeometryAdapterFactory} + * should be used to serialize/deserialize Geometries. */ +@Deprecated public class GeometryDeserializer implements JsonDeserializer { /** diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryGeoJson.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryGeoJson.java index 356435c32..aa039c713 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryGeoJson.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryGeoJson.java @@ -3,16 +3,8 @@ import android.support.annotation.NonNull; import com.google.gson.GsonBuilder; -import com.google.gson.typeadapters.RuntimeTypeAdapterFactory; -import com.mapbox.geojson.BoundingBox; import com.mapbox.geojson.Geometry; -import com.mapbox.geojson.GeometryCollection; -import com.mapbox.geojson.LineString; -import com.mapbox.geojson.MultiLineString; -import com.mapbox.geojson.MultiPoint; -import com.mapbox.geojson.MultiPolygon; -import com.mapbox.geojson.Point; -import com.mapbox.geojson.Polygon; +import com.mapbox.geojson.GeometryAdapterFactory; /** * This is a utility class that helps create a Geometry instance from a JSON string. @@ -30,24 +22,9 @@ public class GeometryGeoJson { */ public static Geometry fromJson(@NonNull String json) { -// final RuntimeTypeAdapterFactory geometryFactory = RuntimeTypeAdapterFactory -// .of(Geometry.class, "type") -// .registerSubtype(GeometryCollection.class, "GeometryCollection") -// .registerSubtype(Point.class, "Point") -// .registerSubtype(MultiPoint.class, "MultiPoint") -// .registerSubtype(LineString.class, "LineString") -// .registerSubtype(MultiLineString.class, "MultiLineString") -// .registerSubtype(Polygon.class, "Polygon") -// .registerSubtype(MultiPolygon.class, "MultiPolygon") -// ; - GsonBuilder gson = new GsonBuilder(); - - gson.registerTypeAdapter(Point.class, new PointDeserializer()); - gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); - gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); - gson.registerTypeAdapter(Geometry.class, new GeometryDeserializer()); + gson.registerTypeAdapterFactory(GeometryAdapterFactory.create()); return gson.create().fromJson(json, Geometry.class); } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryTypeAdapter.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryTypeAdapter.java index 39ff475c1..43e781ca1 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryTypeAdapter.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/GeometryTypeAdapter.java @@ -2,23 +2,21 @@ import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; -import com.google.gson.stream.MalformedJsonException; import com.mapbox.geojson.CoordinateContainer; import com.mapbox.geojson.Geometry; -import com.mapbox.geojson.shifter.CoordinateShifterManager; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; /** * Converts {@code Geometry} instances to JSON and JSON to * instances of {@code Geometry}. * * @since 3.0.0 + * @deprecated this class is deprecated, {@link com.mapbox.geojson.GeometryAdapterFactory} + * should be used to serialize/deserialize Geometries. */ +@Deprecated public class GeometryTypeAdapter extends TypeAdapter { @@ -30,15 +28,13 @@ public void write(JsonWriter out, Geometry value) throws IOException { out.name("bbox").jsonValue(value.bbox().toJson()); } if (value instanceof CoordinateContainer) { - - String coordinates = ((CoordinateContainer) value).coordinates().toString(); - out.name("coordinates").jsonValue(coordinates); + out.name("coordinates").jsonValue(((CoordinateContainer) value).coordinates().toString()); } out.endObject(); } @Override public Geometry read(JsonReader in) throws IOException { - return null; + return null; } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/PointDeserializer.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/PointDeserializer.java index ab2be37d6..8fd88ed88 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/gson/PointDeserializer.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/PointDeserializer.java @@ -4,12 +4,9 @@ import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.mapbox.geojson.BoundingBox; import com.mapbox.geojson.Point; import java.lang.reflect.Type; -import java.util.List; /** * Deserialize the coordinates inside the json into {@link Point}s capturing the same information. @@ -17,7 +14,10 @@ * "Expected BEGIN_OBJECT but was BEGIN_ARRAY". * * @since 1.0.0 + * @deprecated this class is deprecated, {@link com.mapbox.geojson.PointAsCoordinatesTypeAdapter} + * should be used to serialize/deserialize coordinates as Points. */ +@Deprecated public class PointDeserializer implements JsonDeserializer { /** @@ -30,8 +30,9 @@ public PointDeserializer() { } /** - * Deserialize Point object or coordinates - * inside the json into {@link Point}s capturing the same information. + * Deserialize the coordinates inside the json into {@link Point}s capturing the same information. + * Otherwise when deserializing, you'll most likely see this error: Required to handle the + * "Expected BEGIN_OBJECT but was BEGIN_ARRAY". * * @param json a class representing an element of Json * @param typeOfT common superinterface for all types in the Java @@ -43,28 +44,7 @@ public PointDeserializer() { */ @Override public Point deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { - - JsonElement jsonElement = json; - BoundingBox boundingBox = null; - - if (json.isJsonObject()) { - JsonObject jsonObject = json.getAsJsonObject(); - jsonElement = jsonObject.get("type"); - if (jsonElement.isJsonNull()) { - throw new NullPointerException(); - } - - jsonElement = jsonObject.get("bbox"); - if (jsonElement != null && !jsonElement.isJsonNull()) { - boundingBox = context.deserialize(jsonElement, BoundingBox.class); - } - jsonElement = jsonObject.get("coordinates"); - if (jsonElement.isJsonNull()) { - throw new NullPointerException(); - } - } - - JsonArray rawCoordinates = jsonElement.getAsJsonArray(); + JsonArray rawCoordinates = json.getAsJsonArray(); double longitude = rawCoordinates.get(0).getAsDouble(); double latitude = rawCoordinates.get(1).getAsDouble(); @@ -72,10 +52,10 @@ public Point deserialize(JsonElement json, Type typeOfT, JsonDeserializationCont // Includes altitude if (rawCoordinates.size() > 2) { double altitude = rawCoordinates.get(2).getAsDouble(); - return Point.fromLngLat(longitude, latitude, altitude, boundingBox); + return Point.fromLngLat(longitude, latitude, altitude); } // It doesn't have altitude - return Point.fromLngLat(longitude, latitude, boundingBox); + return Point.fromLngLat(longitude, latitude); } } diff --git a/services-geojson/src/main/java/com/mapbox/geojson/gson/PointSerializer.java b/services-geojson/src/main/java/com/mapbox/geojson/gson/PointSerializer.java index d763a7932..b19ae06b1 100644 --- a/services-geojson/src/main/java/com/mapbox/geojson/gson/PointSerializer.java +++ b/services-geojson/src/main/java/com/mapbox/geojson/gson/PointSerializer.java @@ -17,7 +17,10 @@ * double value as per JSON specification. * * @since 1.0.0 + * @deprecated this class is deprecated, {@link com.mapbox.geojson.PointAsCoordinatesTypeAdapter} + * should be used to serialize/deserialize coordinates as Points. */ +@Deprecated public class PointSerializer implements JsonSerializer { /** diff --git a/services-geojson/src/test/java/com/mapbox/geojson/GeoJsonTest.java b/services-geojson/src/test/java/com/mapbox/geojson/GeoJsonTest.java index 4aae71859..c8dd39fbd 100644 --- a/services-geojson/src/test/java/com/mapbox/geojson/GeoJsonTest.java +++ b/services-geojson/src/test/java/com/mapbox/geojson/GeoJsonTest.java @@ -7,6 +7,8 @@ import java.util.ArrayList; import java.util.List; +import static org.junit.Assert.assertEquals; + public class GeoJsonTest extends TestUtils { private static final String GEOJSON_FIXTURE = "sample-geojson-result.json"; @@ -37,6 +39,28 @@ public void testSevenDigitRounding() throws IOException { features.add(Feature.fromGeometry(negRound)); FeatureCollection featureCollection = FeatureCollection.fromFeatures(features); - compareJson(loadJsonFixture(GEOJSON_FIXTURE), featureCollection.toJson()); + + List featureCollectionRounded = + FeatureCollection.fromJson(featureCollection.toJson()).features(); + Point roundDown2 = (Point)featureCollectionRounded.get(0).geometry(); + Point noRound2 = (Point)featureCollectionRounded.get(1).geometry(); + Point matchRound2 = (Point)featureCollectionRounded.get(2).geometry(); + Point roundLat2 = (Point)featureCollectionRounded.get(3).geometry(); + Point roundLon2 = (Point)featureCollectionRounded.get(4).geometry(); + Point largeRound2 = (Point)featureCollectionRounded.get(5).geometry(); + Point negRound2 = (Point)featureCollectionRounded.get(6).geometry(); + + assertEquals(1.1234568, roundDown2.longitude(), DELTA); + assertEquals(1.1234568, roundDown2.latitude(), DELTA); + assertEquals(noRound, noRound2); + assertEquals(matchRound, matchRound2); + assertEquals(roundLat.longitude(), roundLat2.longitude(), DELTA); + assertEquals(1.1234568, roundLat2.latitude(), DELTA); + assertEquals(1.1234568, roundLon2.longitude(), DELTA); + assertEquals(roundLon.latitude(), roundLon2.latitude(), DELTA); + assertEquals(105.1234568, largeRound2.longitude(), DELTA); + assertEquals(largeRound.latitude(), largeRound2.latitude(), DELTA); + assertEquals(-105.1234568, negRound2.longitude(), DELTA); + assertEquals(negRound.latitude(), negRound2.latitude(), DELTA); } } diff --git a/services-geojson/src/test/java/com/mapbox/geojson/GeometryCollectionTest.java b/services-geojson/src/test/java/com/mapbox/geojson/GeometryCollectionTest.java index 2f447a9e5..2221a8e3a 100644 --- a/services-geojson/src/test/java/com/mapbox/geojson/GeometryCollectionTest.java +++ b/services-geojson/src/test/java/com/mapbox/geojson/GeometryCollectionTest.java @@ -125,7 +125,16 @@ public void testSerializable() throws Exception { @Test public void fromJson() throws IOException { - final String json = loadJsonFixture(SAMPLE_GEOMETRYCOLLECTION); + final String json = + " { \"type\": \"GeometryCollection\"," + + " \"bbox\": [120, 40, -120, -40]," + + " \"geometries\": [" + + " { \"type\": \"Point\"," + + " \"bbox\": [110, 30, -110, -30]," + + " \"coordinates\": [100, 0]}," + + " { \"type\": \"LineString\"," + + " \"bbox\": [110, 30, -110, -30]," + + " \"coordinates\": [[101, 0], [102, 1]]}]}"; GeometryCollection geo = GeometryCollection.fromJson(json); assertEquals(geo.type(), "GeometryCollection"); assertEquals(geo.geometries().get(0).type(), "Point"); @@ -134,7 +143,16 @@ public void fromJson() throws IOException { @Test public void toJson() throws IOException { - final String jsonOriginal = loadJsonFixture(SAMPLE_GEOMETRYCOLLECTION); + final String jsonOriginal = + " { \"type\": \"GeometryCollection\"," + + " \"bbox\": [-120, -40, 120, 40]," + + " \"geometries\": [" + + " { \"type\": \"Point\"," + + " \"bbox\": [-110, -30, 110, 30]," + + " \"coordinates\": [100, 0]}," + + " { \"type\": \"LineString\"," + + " \"bbox\": [-110, -30, 110, 30]," + + " \"coordinates\": [[101, 0], [102, 1]]}]}"; List geometries = new ArrayList<>(2); geometries.add(Point.fromLngLat(100, 0, diff --git a/services-geojson/src/test/java/com/mapbox/geojson/GeometryTest.java b/services-geojson/src/test/java/com/mapbox/geojson/GeometryTest.java index b467d0713..3171f3a51 100644 --- a/services-geojson/src/test/java/com/mapbox/geojson/GeometryTest.java +++ b/services-geojson/src/test/java/com/mapbox/geojson/GeometryTest.java @@ -17,10 +17,18 @@ public class GeometryTest extends TestUtils { @Test public void fromJson() throws IOException { - final String json = loadJsonFixture(SAMPLE_GEOMETRY_COLLECTION); + final String json = + " { \"type\": \"GeometryCollection\"," + + " \"bbox\": [120, 40, -120, -40]," + + " \"geometries\": [" + + " { \"type\": \"Point\"," + + " \"bbox\": [110, 30, -110, -30]," + + " \"coordinates\": [100, 0]}," + + " { \"type\": \"LineString\"," + + " \"bbox\": [110, 30, -110, -30]," + + " \"coordinates\": [[101, 0], [102, 1]]}]}"; Geometry geo = GeometryGeoJson.fromJson(json); - //assertEquals(geo.type(), "GeometryCollection"); - int i = 0; + assertEquals(geo.type(), "GeometryCollection"); } @Test diff --git a/services-geojson/src/test/java/com/mapbox/geojson/LineStringTest.java b/services-geojson/src/test/java/com/mapbox/geojson/LineStringTest.java index 111426c53..ad09c8618 100644 --- a/services-geojson/src/test/java/com/mapbox/geojson/LineStringTest.java +++ b/services-geojson/src/test/java/com/mapbox/geojson/LineStringTest.java @@ -127,7 +127,8 @@ public void testSerializable() throws Exception { @Test public void fromJson() throws IOException { - final String json = loadJsonFixture(SAMPLE_LINESTRING_FIXTURE); + final String json = "{\"type\": \"LineString\"," + + " \"coordinates\": [[ 100, 0], [101, 1]]} "; LineString geo = LineString.fromJson(json); assertEquals(geo.type(), "LineString"); assertEquals(geo.coordinates().get(0).longitude(), 100.0, 0.0); @@ -137,7 +138,8 @@ public void fromJson() throws IOException { @Test public void toJson() throws IOException { - final String json = loadJsonFixture(SAMPLE_LINESTRING_FIXTURE); + final String json = "{\"type\": \"LineString\"," + + " \"coordinates\": [[ 100, 0], [101, 1]]} "; LineString geo = LineString.fromJson(json); String geoJsonString = geo.toJson(); compareJson(geoJsonString, json); diff --git a/services-geojson/src/test/java/com/mapbox/geojson/MultiLineStringTest.java b/services-geojson/src/test/java/com/mapbox/geojson/MultiLineStringTest.java index fb4e4ec7a..0c20169fa 100644 --- a/services-geojson/src/test/java/com/mapbox/geojson/MultiLineStringTest.java +++ b/services-geojson/src/test/java/com/mapbox/geojson/MultiLineStringTest.java @@ -125,7 +125,9 @@ public void testSerializable() throws Exception { @Test public void fromJson() throws IOException { - final String json = loadJsonFixture(SAMPLE_MULTILINESTRING); + final String json = "{\"type\": \"MultiLineString\", " + + "\"coordinates\": [[[100, 0],[101, 1]],[[102, 2],[103, 3]]] }"; + MultiLineString geo = MultiLineString.fromJson(json); assertEquals("MultiLineString", geo.type()); assertEquals(geo.coordinates().get(0).get(0).longitude(), 100.0, DELTA); @@ -135,7 +137,8 @@ public void fromJson() throws IOException { @Test public void toJson() throws IOException { - final String json = loadJsonFixture(SAMPLE_MULTILINESTRING); + final String json = "{\"type\": \"MultiLineString\", " + + "\"coordinates\": [[[100, 0],[101, 1]],[[102, 2],[103, 3]]] }"; MultiLineString geo = MultiLineString.fromJson(json); compareJson(json, geo.toJson()); } diff --git a/services-geojson/src/test/java/com/mapbox/geojson/MultiPointTest.java b/services-geojson/src/test/java/com/mapbox/geojson/MultiPointTest.java index e6f0b7782..f7dc684c9 100644 --- a/services-geojson/src/test/java/com/mapbox/geojson/MultiPointTest.java +++ b/services-geojson/src/test/java/com/mapbox/geojson/MultiPointTest.java @@ -94,7 +94,8 @@ public void testSerializable() throws Exception { @Test public void fromJson() throws IOException { - final String json = loadJsonFixture(SAMPLE_MULTIPOINT); + final String json = "{ \"type\": \"MultiPoint\"," + + "\"coordinates\": [ [100, 0], [101, 1] ] } "; MultiPoint geo = MultiPoint.fromJson(json); assertEquals(geo.type(), "MultiPoint"); assertEquals(geo.coordinates().get(0).longitude(), 100.0, DELTA); @@ -107,7 +108,8 @@ public void fromJson() throws IOException { @Test public void toJson() throws IOException { - final String json = loadJsonFixture(SAMPLE_MULTIPOINT); + final String json = "{ \"type\": \"MultiPoint\"," + + "\"coordinates\": [ [100, 0], [101, 1] ] } "; MultiPoint geo = MultiPoint.fromJson(json); compareJson(json, geo.toJson()); } diff --git a/services-geojson/src/test/java/com/mapbox/geojson/MultiPolygonTest.java b/services-geojson/src/test/java/com/mapbox/geojson/MultiPolygonTest.java index 57dca1e2c..56661b7d8 100644 --- a/services-geojson/src/test/java/com/mapbox/geojson/MultiPolygonTest.java +++ b/services-geojson/src/test/java/com/mapbox/geojson/MultiPolygonTest.java @@ -142,7 +142,10 @@ public void testSerializable() throws Exception { @Test public void fromJson() throws IOException { - final String json = loadJsonFixture(SAMPLE_MULTIPOLYGON); + final String json = "{\"type\":\"MultiPolygon\",\"coordinates\": " + + " [[[[102, 2], [103, 2], [103, 3], [102, 3], [102, 2]]]," + + " [[[100, 0], [101, 0], [101, 1], [100, 1], [100, 0]]," + + " [[100.2, 0.2], [100.2, 0.8], [100.8, 0.8], [100.8, 0.2], [100.2, 0.2]]]]}"; MultiPolygon geo = MultiPolygon.fromJson(json); assertEquals(geo.type(), "MultiPolygon"); assertEquals(geo.coordinates().get(0).get(0).get(0).longitude(), 102.0, DELTA); @@ -152,7 +155,11 @@ public void fromJson() throws IOException { @Test public void toJson() throws IOException { - final String json = loadJsonFixture(SAMPLE_MULTIPOLYGON); + final String json = "{\"type\":\"MultiPolygon\",\"coordinates\": " + + " [[[[102, 2], [103, 2], [103, 3], [102, 3], [102, 2]]]," + + " [[[100, 0], [101, 0], [101, 1], [100, 1], [100, 0]]," + + " [[100.2, 0.2], [100.2, 0.8], [100.8, 0.8], [100.8, 0.2], [100.2, 0.2]]]]}"; + MultiPolygon geo = MultiPolygon.fromJson(json); compareJson(json, geo.toJson()); } diff --git a/services-geojson/src/test/java/com/mapbox/geojson/PolygonTest.java b/services-geojson/src/test/java/com/mapbox/geojson/PolygonTest.java index c8d018f8c..f99e97fa1 100644 --- a/services-geojson/src/test/java/com/mapbox/geojson/PolygonTest.java +++ b/services-geojson/src/test/java/com/mapbox/geojson/PolygonTest.java @@ -230,7 +230,8 @@ public void testSerializable() throws Exception { @Test public void fromJson() throws IOException { - final String json = loadJsonFixture(SAMPLE_POLYGON); + final String json = "{\"type\": \"Polygon\", " + + "\"coordinates\": [[[100, 0], [101, 0], [101, 1], [100, 1],[100, 0]]]}"; Polygon geo = Polygon.fromJson(json); assertEquals("Polygon", geo.type()); assertEquals(100.0, geo.coordinates().get(0).get(0).longitude(), DELTA); @@ -240,7 +241,9 @@ public void fromJson() throws IOException { @Test public void fromJsonHoles() throws IOException { - final String json = loadJsonFixture(SAMPLE_POLYGON_HOLES); + final String json = "{\"type\": \"Polygon\", " + + "\"coordinates\": [[[100, 0], [101, 0], [101, 1], [100, 1],[100, 0]], " + + " [[100.8, 0.8],[100.8, 0.2],[100.2, 0.2],[100.2, 0.8],[100.8, 0.8]]]}"; Polygon geo = Polygon.fromJson(json); assertEquals("Polygon", geo.type()); assertEquals(100.0, geo.coordinates().get(0).get(0).longitude(), DELTA); @@ -253,14 +256,17 @@ public void fromJsonHoles() throws IOException { @Test public void toJson() throws IOException { - final String json = loadJsonFixture(SAMPLE_POLYGON); + final String json = "{\"type\": \"Polygon\", " + + "\"coordinates\": [[[100, 0], [101, 0], [101, 1], [100, 1],[100, 0]]]}"; Polygon geo = Polygon.fromJson(json); compareJson(json, geo.toJson()); } @Test public void toJsonHoles() throws IOException { - final String json = loadJsonFixture(SAMPLE_POLYGON_HOLES); + final String json = "{\"type\": \"Polygon\", " + + "\"coordinates\": [[[100, 0], [101, 0], [101, 1], [100, 1],[100, 0]], " + + " [[100.8, 0.8],[100.8, 0.2],[100.2, 0.2],[100.2, 0.8],[100.8, 0.8]]]}"; Polygon geo = Polygon.fromJson(json); compareJson(json, geo.toJson()); } diff --git a/services-geojson/src/test/java/com/mapbox/geojson/gson/PointDeserializerTest.java b/services-geojson/src/test/java/com/mapbox/geojson/gson/PointDeserializerTest.java index 6a5f38cb9..e1d3d92d8 100644 --- a/services-geojson/src/test/java/com/mapbox/geojson/gson/PointDeserializerTest.java +++ b/services-geojson/src/test/java/com/mapbox/geojson/gson/PointDeserializerTest.java @@ -34,7 +34,7 @@ public void deserialize_sanity() throws Exception { @Test public void point_doesNotDeserializeObject() throws Exception { - thrown.expect(NullPointerException.class); + thrown.expect(JsonSyntaxException.class); String jsonString = "{ \"coordinates\": [100.0, 0.0, 200.0]}"; GsonBuilder gsonBuilder = new GsonBuilder() diff --git a/services-tilequery/src/main/java/com/mapbox/api/tilequery/MapboxTilequery.java b/services-tilequery/src/main/java/com/mapbox/api/tilequery/MapboxTilequery.java index 8687f1a6c..fe666b9d7 100644 --- a/services-tilequery/src/main/java/com/mapbox/api/tilequery/MapboxTilequery.java +++ b/services-tilequery/src/main/java/com/mapbox/api/tilequery/MapboxTilequery.java @@ -10,14 +10,10 @@ import com.mapbox.core.exceptions.ServicesException; import com.mapbox.core.utils.MapboxUtils; import com.mapbox.core.utils.TextUtils; -import com.mapbox.geojson.BoundingBox; import com.mapbox.geojson.FeatureCollection; -import com.mapbox.geojson.Geometry; +import com.mapbox.geojson.GeometryAdapterFactory; import com.mapbox.geojson.Point; -import com.mapbox.geojson.gson.BoundingBoxDeserializer; import com.mapbox.geojson.gson.GeoJsonAdapterFactory; -import com.mapbox.geojson.gson.GeometryDeserializer; -import com.mapbox.geojson.gson.PointDeserializer; import java.io.IOException; import java.util.List; @@ -47,11 +43,10 @@ protected MapboxTilequery() { @Override protected GsonBuilder getGsonBuilder() { + return new GsonBuilder() .registerTypeAdapterFactory(GeoJsonAdapterFactory.create()) - .registerTypeAdapter(Point.class, new PointDeserializer()) - .registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()) - .registerTypeAdapter(Geometry.class, new GeometryDeserializer()); + .registerTypeAdapterFactory(GeometryAdapterFactory.create()); } @Override