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);
}
}
}