package org.mongodb.morphia.geo;

import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.mongodb.morphia.converters.SimpleValueConverter;
import org.mongodb.morphia.converters.TypeConverter;
import org.mongodb.morphia.mapping.MappedField;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static org.mongodb.morphia.geo.GeoJsonType.LINE_STRING;
import static org.mongodb.morphia.geo.GeoJsonType.MULTI_LINE_STRING;
import static org.mongodb.morphia.geo.GeoJsonType.MULTI_POINT;
import static org.mongodb.morphia.geo.GeoJsonType.MULTI_POLYGON;
import static org.mongodb.morphia.geo.GeoJsonType.POINT;
import static org.mongodb.morphia.geo.GeoJsonType.POLYGON;

Converter that understands most Geometry instances are effectively just lists of either other geometry objects or double coordinates. Recursively encodes and decodes Geometry objects, but needs to be instantiated with a List of GeometryFactory instances that represented the hierarchy of Geometries that make up the required Geometry object.

Overridden by subclasses to define exact behaviour for specific Geometry concrete classes.
/** * Converter that understands most Geometry instances are effectively just lists of either other geometry objects or double coordinates. * Recursively encodes and decodes Geometry objects, but needs to be instantiated with a List of GeometryFactory instances that represented * the hierarchy of Geometries that make up the required Geometry object. * <p/> * Overridden by subclasses to define exact behaviour for specific Geometry concrete classes. */
public class GeometryShapeConverter extends TypeConverter implements SimpleValueConverter { private final GeoJsonType geoJsonType; private final List<GeometryFactory> factories; GeometryShapeConverter(final GeoJsonType... geoJsonTypes) { super(geoJsonTypes[0].getTypeClass()); geoJsonType = geoJsonTypes[0]; this.factories = Arrays.<GeometryFactory>asList(geoJsonTypes); } @Override public Geometry decode(final Class<?> targetClass, final Object fromDBObject, final MappedField optionalExtraInfo) { return decodeObject((List) ((DBObject) fromDBObject).get("coordinates"), factories); } @Override public Object encode(final Object value, final MappedField optionalExtraInfo) { if (value != null) { Object encodedObjects = encodeObjects(((Geometry) value).getCoordinates()); return new BasicDBObject("type", geoJsonType.getType()) .append("coordinates", encodedObjects); } else { return null; } } /* * We're expecting a List that can be turned into a geometry using a series of factories */ @SuppressWarnings("unchecked") // always have unchecked casts when dealing with raw classes private Geometry decodeObject(final List mongoDBGeometry, final List<GeometryFactory> geometryFactories) { GeometryFactory factory = geometryFactories.get(0); if (geometryFactories.size() == 1) { // This should be the last list, so no need to decode further return factory.createGeometry(mongoDBGeometry); } else { List<Geometry> decodedObjects = new ArrayList<Geometry>(); for (final Object objectThatNeedsDecoding : mongoDBGeometry) { // MongoDB geometries are lists of lists of lists... decodedObjects.add(decodeObject((List) objectThatNeedsDecoding, geometryFactories.subList(1, geometryFactories.size()))); } return factory.createGeometry(decodedObjects); } } private Object encodeObjects(final List value) { List<Object> encodedObjects = new ArrayList<Object>(); for (final Object object : value) { if (object instanceof Geometry) { //iterate through the list of geometry objects recursively until you find the lowest-level encodedObjects.add(encodeObjects(((Geometry) object).getCoordinates())); } else { encodedObjects.add(getMapper().getConverters().encode(object)); } } return encodedObjects; }
Extends and therefore configures GeometryShapeConverter to provide the specific configuration for converting MultiPolygon objects to and from MongoDB representations of the GeoJson.
/** * Extends and therefore configures GeometryShapeConverter to provide the specific configuration for converting MultiPolygon objects to * and from <a href="http://geojson.org/geojson-spec.html#id7">MongoDB representations</a> of the GeoJson. */
public static class MultiPolygonConverter extends GeometryShapeConverter {
Creates a new MultiPolygonConverter.
/** * Creates a new MultiPolygonConverter. */
public MultiPolygonConverter() { super(MULTI_POLYGON, POLYGON, LINE_STRING, POINT); } }
Defines a new PolygonConverter. This extends and therefore configures GeometryShapeConverter to provide the specific configuration for converting Polygon objects to and from MongoDB representations of the GeoJson.
/** * Defines a new PolygonConverter. This extends and therefore configures GeometryShapeConverter to provide the specific * configuration for converting Polygon objects to and from <a href="http://geojson.org/geojson-spec.html#id4">MongoDB * representations</a> of the GeoJson. */
public static class PolygonConverter extends GeometryShapeConverter {
Creates a new PolygonConverter.
/** * Creates a new PolygonConverter. */
public PolygonConverter() { super(POLYGON, LINE_STRING, POINT); } }
Defines a new MultiLineStringConverter. This extends and therefore configures GeometryShapeConverter to provide the specific configuration for converting MultiLineString objects to and from MongoDB representations of the GeoJson.
/** * Defines a new MultiLineStringConverter. This extends and therefore configures GeometryShapeConverter to provide the specific * configuration for converting MultiLineString objects to and from <a href="http://geojson.org/geojson-spec.html#id6">MongoDB * representations</a> of the GeoJson. */
public static class MultiLineStringConverter extends GeometryShapeConverter {
Creates a new MultiLineStringConverter.
/** * Creates a new MultiLineStringConverter. */
public MultiLineStringConverter() { super(MULTI_LINE_STRING, LINE_STRING, POINT); } }
Defines a new MultiPointConverter. This extends and therefore configures GeometryShapeConverter to provide the specific configuration for converting MultiPoint objects to and from MongoDB representations of the GeoJson.
/** * Defines a new MultiPointConverter. This extends and therefore configures GeometryShapeConverter to provide the specific * configuration for converting MultiPoint objects to and from <a href="http://geojson.org/geojson-spec.html#id5">MongoDB * representations</a> of the GeoJson. */
public static class MultiPointConverter extends GeometryShapeConverter {
Creates a new MultiPointConverter.
/** * Creates a new MultiPointConverter. */
public MultiPointConverter() { super(MULTI_POINT, POINT); } }
Defines a new LineStringConverter. This extends and therefore configures GeometryShapeConverter to provide the specific configuration for converting LineString objects to and from MongoDB representations of the GeoJson.
/** * Defines a new LineStringConverter. This extends and therefore configures GeometryShapeConverter to provide the specific * configuration for converting LineString objects to and from <a href="http://geojson.org/geojson-spec.html#id3">MongoDB * representations</a> of the GeoJson. */
public static class LineStringConverter extends GeometryShapeConverter {
Creates a new LineStringConverter.
/** * Creates a new LineStringConverter. */
public LineStringConverter() { super(LINE_STRING, POINT); } }
Defines a new PointConverter. This extends and therefore configures GeometryShapeConverter to provide the specific configuration for converting Point objects to and from MongoDB representations of the GeoJson.
/** * Defines a new PointConverter. This extends and therefore configures GeometryShapeConverter to provide the specific configuration * for converting Point objects to and from <a href="http://geojson.org/geojson-spec.html#id3">MongoDB representations</a> of the * GeoJson. */
public static class PointConverter extends GeometryShapeConverter {
Creates a new PointConverter.
/** * Creates a new PointConverter. */
public PointConverter() { super(POINT); } } }