com.ibm.common.geojson.as2.GeoAdapter.java Source code

Java tutorial

Introduction

Here is the source code for com.ibm.common.geojson.as2.GeoAdapter.java

Source

/**
 * Copyright 2013 OpenSocial Foundation
 * Copyright 2013 International Business Machines Corporation
 *
 * 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.
 *
 * Utility library for working with Activity Streams Actions
 * Requires underscorejs.
 *
 * @author James M Snell (jasnell@us.ibm.com)
 */
package com.ibm.common.geojson.as2;

import static com.google.common.base.Preconditions.checkArgument;

import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Map;

import com.google.common.base.Enums;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.ibm.common.activitystreams.internal.Adapter;
import com.ibm.common.geojson.BoundingBox;
import com.ibm.common.geojson.CRS;
import com.ibm.common.geojson.Feature;
import com.ibm.common.geojson.FeatureCollection;
import com.ibm.common.geojson.GeoMakers;
import com.ibm.common.geojson.GeoObject;
import com.ibm.common.geojson.Geometry;
import com.ibm.common.geojson.Geometry.CoordinateGeometry;
import com.ibm.common.geojson.GeometryCollection;
import com.ibm.common.geojson.LineString;
import com.ibm.common.geojson.MultiLineString;
import com.ibm.common.geojson.MultiPoint;
import com.ibm.common.geojson.MultiPolygon;
import com.ibm.common.geojson.Point;
import com.ibm.common.geojson.Polygon;
import com.ibm.common.geojson.Position;

@SuppressWarnings("rawtypes")
public class GeoAdapter extends Adapter<GeoObject> {

    @Override
    public JsonElement serialize(GeoObject geo, Type type, JsonSerializationContext context) {

        JsonObject obj = new JsonObject();
        obj.add("type", context.serialize(geo.type(), GeoObject.Type.class));
        switch (geo.type()) {
        case POINT:
        case MULTIPOINT:
        case LINESTRING:
        case MULTILINESTRING:
        case MULTIPOLYGON:
        case POLYGON:
            CoordinateGeometry c = (CoordinateGeometry) geo;
            obj.add("coordinates", context.serialize(c.coordinates(), Iterable.class));
            break;
        case GEOMETRYCOLLECTION:
            GeometryCollection gc = (GeometryCollection) geo;
            obj.add("geometries", context.serialize(gc.geometries(), Iterable.class));
            break;
        case FEATURE:
            Feature feature = (Feature) geo;
            if (feature.id() != null)
                obj.addProperty("id", feature.id());
            Geometry<?, ?> geometry = feature.geometry();
            Map<String, Object> properties = feature.properties();
            if (geometry != null)
                obj.add("geometry", context.serialize(feature.geometry()));
            if (properties != null)
                obj.add("properties", context.serialize(properties));
            break;
        case FEATURECOLLECTION:
            FeatureCollection fc = (FeatureCollection) geo;
            obj.add("features", context.serialize(fc.features(), Iterable.class));
            break;
        default:
            break;

        }
        if (geo.boundingBox() != null) {
            BoundingBox bb = geo.boundingBox();
            obj.add("bbox", context.serialize(bb, Iterable.class));
        }
        if (geo.crs() != null) {
            CRS crs = geo.crs();
            JsonObject crsobj = new JsonObject();
            crsobj.addProperty("name", crs.type());
            if (crs.size() > 0)
                crsobj.add("properties", context.serialize(crs.properties()));
            obj.add("crs", crsobj);
        }
        return obj;
    }

    private Position toPosition(float[] pos) {
        Position.Builder b = new Position.Builder();
        for (int n = 0; n < pos.length; n++) {
            if (n == 0)
                b.northing(pos[n]);
            else if (n == 1)
                b.easting(pos[n]);
            else if (n == 2)
                b.altitude(pos[n]);
            else
                b.additional(pos[n]);
        }
        return b.get();
    }

    @Override
    public GeoObject deserialize(JsonElement element, Type type, JsonDeserializationContext context)
            throws JsonParseException {
        GeoObject.Builder geo = null;
        checkArgument(element.isJsonObject());
        JsonObject obj = element.getAsJsonObject();
        checkArgument(obj.has("type"));
        GeoObject.Type et = Enums.getIfPresent(GeoObject.Type.class, obj.get("type").getAsString().toUpperCase())
                .orNull();
        checkArgument(et != null);
        switch (et) {
        case FEATURE:
            geo = GeoMakers.feature();
            break;
        case FEATURECOLLECTION:
            geo = GeoMakers.featureCollection();
            type = Feature.class;
            break;
        case GEOMETRYCOLLECTION:
            geo = GeoMakers.geometryCollection();
            type = Geometry.class;
            break;
        case LINESTRING:
            geo = GeoMakers.linestring();
            type = Position.class;
            break;
        case MULTILINESTRING:
            geo = GeoMakers.multiLineString();
            type = LineString.class;
            break;
        case MULTIPOINT:
            geo = GeoMakers.multipoint();
            type = Position.class;
            break;
        case MULTIPOLYGON:
            geo = GeoMakers.multiPolygon();
            type = Polygon.class;
            break;
        case POINT:
            geo = GeoMakers.point();
            type = null;
            break;
        case POLYGON:
            geo = GeoMakers.polygon();
            type = LineString.class;
            break;
        }

        for (Map.Entry<String, JsonElement> entry : obj.entrySet()) {
            JsonElement el = entry.getValue();
            String name = entry.getKey();
            if ("crs".equals(name)) {
                CRS.Builder cb = new CRS.Builder();
                JsonObject o = el.getAsJsonObject();
                if (o.has("type"))
                    cb.type(o.get("type").getAsString());
                if (o.has("properties")) {
                    JsonObject p = o.get("properties").getAsJsonObject();
                    for (Map.Entry<String, JsonElement> e : p.entrySet()) {
                        cb.set(e.getKey(), context.deserialize(e.getValue(), Object.class));
                    }
                }
                geo.crs(cb.get());
            } else if ("properties".equals(name)) {
                geo.set("properties", context.deserialize(el, Map.class));
            } else if ("bbox".equals(name)) {
                BoundingBox.Builder bb = new BoundingBox.Builder();
                float[] points = context.deserialize(el, float[].class);
                bb.add(points);
                geo.boundingBox(bb.get());
            } else if ("features".equals(name)) {
                Feature[] features = context.deserialize(el, Feature[].class);
                FeatureCollection.Builder fcb = (FeatureCollection.Builder) geo;
                for (Feature f : features)
                    fcb.add(f);
            } else if ("coordinates".equals(name)) {
                switch (et) {
                case LINESTRING: {
                    LineString.Builder lsb = (LineString.Builder) geo;
                    float[][] positions = context.deserialize(el, float[][].class);
                    boolean ring = ring(positions);
                    if (ring)
                        lsb.linearRing();
                    for (int n = 0; n < positions.length; n++) {
                        if (!ring || (ring && n < positions.length - 1))
                            lsb.add(toPosition(positions[n]));
                    }
                    break;
                }
                case MULTIPOINT: {
                    MultiPoint.Builder lsb = (MultiPoint.Builder) geo;
                    float[][] positions = context.deserialize(el, float[][].class);
                    for (float[] pos : positions)
                        lsb.add(toPosition(pos));
                    break;
                }
                case MULTILINESTRING: {
                    MultiLineString.Builder mlb = (MultiLineString.Builder) geo;
                    float[][][] positions = context.deserialize(el, float[][][].class);
                    for (float[][] lines : positions) {
                        LineString.Builder lsb = GeoMakers.linestring();
                        boolean ring = ring(lines);
                        if (ring)
                            lsb.linearRing();
                        for (int n = 0; n < lines.length; n++) {
                            if (!ring || (ring && n < lines.length - 1))
                                lsb.add(toPosition(lines[n]));
                        }
                        for (float[] pos : lines)
                            lsb.add(toPosition(pos));
                        mlb.add(lsb);
                    }
                    break;
                }
                case POLYGON: {
                    Polygon.Builder mlb = (Polygon.Builder) geo;
                    float[][][] positions = context.deserialize(el, float[][][].class);
                    for (float[][] lines : positions) {
                        LineString.Builder lsb = GeoMakers.linestring();
                        for (float[] pos : lines)
                            lsb.add(toPosition(pos));
                        mlb.add(lsb);
                    }
                    break;
                }
                case MULTIPOLYGON: {
                    MultiPolygon.Builder mpb = (MultiPolygon.Builder) geo;
                    float[][][][] positions = context.deserialize(el, float[][][][].class);
                    for (float[][][] polygons : positions) {
                        Polygon.Builder pb = GeoMakers.polygon();
                        for (float[][] lines : polygons) {
                            LineString.Builder lsb = GeoMakers.linestring();
                            for (float[] pos : lines)
                                lsb.add(toPosition(pos));
                            pb.add(lsb);
                        }
                        mpb.add(pb);
                    }
                    break;
                }
                case POINT:
                    Point.Builder pb = (Point.Builder) geo;
                    float[] position = context.deserialize(el, float[].class);
                    pb.position(toPosition(position));
                    break;
                default:
                    break;
                }
            } else if ("geometries".equals(name)) {
                Geometry[] geos = context.deserialize(el, Geometry[].class);
                GeometryCollection.Builder fcb = (GeometryCollection.Builder) geo;
                for (Geometry<?, ?> g : geos)
                    fcb.add(g);
            } else {
                if (el.isJsonArray()) {
                    geo.set(name, context.deserialize(el, Object.class));
                } else if (el.isJsonObject()) {
                    geo.set(name, context.deserialize(el, GeoObject.class));
                } else if (el.isJsonPrimitive()) {
                    JsonPrimitive p = el.getAsJsonPrimitive();
                    if (p.isBoolean())
                        geo.set(name, p.getAsBoolean());
                    else if (p.isNumber())
                        geo.set(name, p.getAsNumber());
                    else if (p.isString())
                        geo.set(name, p.getAsString());
                }
            }
        }

        return geo.get();
    }

    private static boolean ring(float[][] line) {
        return ring(first(line), last(line));
    }

    private static boolean ring(float[] p1, float[] p2) {
        return Arrays.equals(p1, p2);
    }

    private static float[] first(float[][] line) {
        if (line.length == 0)
            return null;
        return line[0];
    }

    private static float[] last(float[][] line) {
        if (line.length == 0)
            return null;
        return line[line.length - 1];
    }
}