diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/GeoConverters.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/GeoConverters.java index 7644912b0..6defb3b6a 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/GeoConverters.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/GeoConverters.java @@ -50,7 +50,7 @@ import com.mongodb.DBObject; /** * Wrapper class to contain useful geo structure converters for the usage with Mongo. - * + * * @author Thomas Darimont * @author Oliver Gierke * @author Christoph Strobl @@ -66,7 +66,7 @@ abstract class GeoConverters { /** * Returns the geo converters to be registered. - * + * * @return */ @SuppressWarnings("unchecked") @@ -92,12 +92,13 @@ abstract class GeoConverters { , DbObjectToGeoJsonMultiLineStringConverter.INSTANCE // , DbObjectToGeoJsonMultiPointConverter.INSTANCE // , DbObjectToGeoJsonMultiPolygonConverter.INSTANCE // - , DbObjectToGeoJsonGeometryCollectionConverter.INSTANCE); + , DbObjectToGeoJsonGeometryCollectionConverter.INSTANCE // + , DbObjectToGeoJsonConverter.INSTANCE); } /** * Converts a {@link List} of {@link Double}s into a {@link Point}. - * + * * @author Thomas Darimont * @since 1.5 */ @@ -129,7 +130,7 @@ abstract class GeoConverters { /** * Converts a {@link Point} into a {@link List} of {@link Double}s. - * + * * @author Thomas Darimont * @since 1.5 */ @@ -149,7 +150,7 @@ abstract class GeoConverters { /** * Converts a {@link Box} into a {@link BasicDBList}. - * + * * @author Thomas Darimont * @since 1.5 */ @@ -178,7 +179,7 @@ abstract class GeoConverters { /** * Converts a {@link BasicDBList} into a {@link Box}. - * + * * @author Thomas Darimont * @since 1.5 */ @@ -207,7 +208,7 @@ abstract class GeoConverters { /** * Converts a {@link Circle} into a {@link BasicDBList}. - * + * * @author Thomas Darimont * @since 1.5 */ @@ -236,7 +237,7 @@ abstract class GeoConverters { /** * Converts a {@link DBObject} into a {@link Circle}. - * + * * @author Thomas Darimont * @since 1.5 */ @@ -278,7 +279,7 @@ abstract class GeoConverters { /** * Converts a {@link Sphere} into a {@link BasicDBList}. - * + * * @author Thomas Darimont * @since 1.5 */ @@ -307,7 +308,7 @@ abstract class GeoConverters { /** * Converts a {@link BasicDBList} into a {@link Sphere}. - * + * * @author Thomas Darimont * @since 1.5 */ @@ -349,7 +350,7 @@ abstract class GeoConverters { /** * Converts a {@link Polygon} into a {@link BasicDBList}. - * + * * @author Thomas Darimont * @since 1.5 */ @@ -383,7 +384,7 @@ abstract class GeoConverters { /** * Converts a {@link BasicDBList} into a {@link Polygon}. - * + * * @author Thomas Darimont * @since 1.5 */ @@ -419,7 +420,7 @@ abstract class GeoConverters { /** * Converts a {@link Sphere} into a {@link BasicDBList}. - * + * * @author Thomas Darimont * @since 1.5 */ @@ -757,7 +758,7 @@ abstract class GeoConverters { * @author Christoph Strobl * @since 1.7 */ - static enum DbObjectToGeoJsonGeometryCollectionConverter implements Converter { + enum DbObjectToGeoJsonGeometryCollectionConverter implements Converter { INSTANCE; @@ -778,8 +779,9 @@ abstract class GeoConverters { List> geometries = new ArrayList>(); for (Object o : (List) source.get("geometries")) { - geometries.add(convertGeometries((DBObject) o)); + geometries.add(toGenericGeoJson((DBObject) o)); } + return new GeoJsonGeometryCollection(geometries); } @@ -820,7 +822,7 @@ abstract class GeoConverters { /** * Converts a coordinate pairs nested in in {@link BasicDBList} into {@link GeoJsonPoint}s. - * + * * @param listOfCoordinatePairs * @return * @since 1.7 @@ -844,7 +846,7 @@ abstract class GeoConverters { /** * Converts a coordinate pairs nested in in {@link BasicDBList} into {@link GeoJsonPolygon}. - * + * * @param dbList * @return * @since 1.7 @@ -853,6 +855,63 @@ abstract class GeoConverters { return new GeoJsonPolygon(toListOfPoint((BasicDBList) dbList.get(0))); } + /** + * Converter implementation transforming a {@link DbObject} into a concrete {@link GeoJson} based on the embedded + * {@literal type} information. + * + * @since 2.1 + * @author Christoph Strobl + */ + @ReadingConverter + enum DbObjectToGeoJsonConverter implements Converter { + INSTANCE; + + /* + * (non-Javadoc) + * @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object) + */ + @Override + public GeoJson convert(DBObject source) { + return toGenericGeoJson(source); + } + } + + private static GeoJson toGenericGeoJson(DBObject source) { + + String type = String.class.cast(source.get("type")); + + if ("point".equalsIgnoreCase(type)) { + return DbObjectToGeoJsonPointConverter.INSTANCE.convert(source); + } + + if ("multipoint".equalsIgnoreCase(type)) { + return DbObjectToGeoJsonMultiPointConverter.INSTANCE.convert(source); + } + + if ("linestring".equalsIgnoreCase(type)) { + return DbObjectToGeoJsonLineStringConverter.INSTANCE.convert(source); + } + + if ("multilinestring".equalsIgnoreCase(type)) { + return DbObjectToGeoJsonMultiLineStringConverter.INSTANCE.convert(source); + } + + if ("polygon".equalsIgnoreCase(type)) { + return DbObjectToGeoJsonPolygonConverter.INSTANCE.convert(source); + } + + if ("multipolygon".equalsIgnoreCase(type)) { + return DbObjectToGeoJsonMultiPolygonConverter.INSTANCE.convert(source); + } + + if ("geometrycollection".equalsIgnoreCase(type)) { + return DbObjectToGeoJsonGeometryCollectionConverter.INSTANCE.convert(source); + } + + throw new IllegalArgumentException( + String.format("No converter found capable of converting GeoJson type %s.", type)); + } + private static double toPrimitiveDoubleValue(Object value) { Assert.isInstanceOf(Number.class, value, "Argument must be a Number."); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/geo/GeoJsonTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/geo/GeoJsonTests.java index 9a8e79e95..e4d65d348 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/geo/GeoJsonTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/geo/GeoJsonTests.java @@ -20,6 +20,8 @@ import static org.junit.Assert.*; import static org.springframework.data.mongodb.core.query.Criteria.*; import static org.springframework.data.mongodb.core.query.Query.*; +import lombok.Data; + import java.util.Arrays; import java.util.List; @@ -192,8 +194,9 @@ public class GeoJsonTests { DocumentWithPropertyUsingGeoJsonType obj = new DocumentWithPropertyUsingGeoJsonType(); obj.id = "geoJsonMultiLineString"; - obj.geoJsonMultiLineString = new GeoJsonMultiLineString(Arrays.asList(new GeoJsonLineString(new Point(0, 0), - new Point(0, 1), new Point(1, 1)), new GeoJsonLineString(new Point(199, 0), new Point(2, 3)))); + obj.geoJsonMultiLineString = new GeoJsonMultiLineString( + Arrays.asList(new GeoJsonLineString(new Point(0, 0), new Point(0, 1), new Point(1, 1)), + new GeoJsonLineString(new Point(199, 0), new Point(2, 3)))); template.save(obj); @@ -223,8 +226,8 @@ public class GeoJsonTests { DocumentWithPropertyUsingGeoJsonType obj = new DocumentWithPropertyUsingGeoJsonType(); obj.id = "geoJsonMultiPolygon"; - obj.geoJsonMultiPolygon = new GeoJsonMultiPolygon(Arrays.asList(new GeoJsonPolygon(new Point(0, 0), - new Point(0, 1), new Point(1, 1), new Point(0, 0)))); + obj.geoJsonMultiPolygon = new GeoJsonMultiPolygon( + Arrays.asList(new GeoJsonPolygon(new Point(0, 0), new Point(0, 1), new Point(1, 1), new Point(0, 0)))); template.save(obj); @@ -239,9 +242,8 @@ public class GeoJsonTests { DocumentWithPropertyUsingGeoJsonType obj = new DocumentWithPropertyUsingGeoJsonType(); obj.id = "geoJsonGeometryCollection"; - obj.geoJsonGeometryCollection = new GeoJsonGeometryCollection(Arrays.> asList( - new GeoJsonPoint(100, 200), new GeoJsonPolygon(new Point(0, 0), new Point(0, 1), new Point(1, 1), new Point(1, - 0), new Point(0, 0)))); + obj.geoJsonGeometryCollection = new GeoJsonGeometryCollection(Arrays.> asList(new GeoJsonPoint(100, 200), + new GeoJsonPolygon(new Point(0, 0), new Point(0, 1), new Point(1, 1), new Point(1, 0), new Point(0, 0)))); template.save(obj); @@ -288,7 +290,8 @@ public class GeoJsonTests { new CollectionCallback() { @Override - public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException { + public Object doInCollection(DBCollection collection) + throws MongoException, DataAccessException { BasicDBObject pointRepresentation = new BasicDBObject(); pointRepresentation.put("type", "Point"); @@ -313,7 +316,8 @@ public class GeoJsonTests { new CollectionCallback() { @Override - public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException { + public Object doInCollection(DBCollection collection) + throws MongoException, DataAccessException { BasicDBObject lineStringRepresentation = new BasicDBObject(); lineStringRepresentation.put("type", "LineString"); @@ -335,6 +339,27 @@ public class GeoJsonTests { is(equalTo(new GeoJsonLineString(new Point(0D, 0D), new Point(1, 1))))); } + @Test // DATAMONGO-1466 + public void readGeoJsonBasedOnEmbeddedTypeInformation() { + + Point first = new Point(-73.99756, 40.73083); + Point second = new Point(-73.99756, 40.741404); + Point third = new Point(-73.988135, 40.741404); + Point fourth = new Point(-73.988135, 40.73083); + + GeoJsonPolygon polygon = new GeoJsonPolygon(first, second, third, fourth, first); + + ConcreteGeoJson source = new ConcreteGeoJson(); + source.shape = polygon; + source.id = "id-1"; + + template.save(source); + + OpenGeoJson target = template.findOne(query(where("id").is(source.id)), OpenGeoJson.class); + + assertThat(target.shape, is(equalTo((GeoJson) source.shape))); + } + private void addVenues() { template.insert(new Venue2DSphere("Penn Station", -73.99408, 40.75057)); @@ -353,8 +378,8 @@ public class GeoJsonTests { protected void createIndex() { dropIndex(); - template.indexOps(Venue2DSphere.class).ensureIndex( - new GeospatialIndex("location").typed(GeoSpatialIndexType.GEO_2DSPHERE)); + template.indexOps(Venue2DSphere.class) + .ensureIndex(new GeospatialIndex("location").typed(GeoSpatialIndexType.GEO_2DSPHERE)); } protected void dropIndex() { @@ -414,4 +439,18 @@ public class GeoJsonTests { GeoJsonGeometryCollection geoJsonGeometryCollection; } + @Data + @Document(collection = "geo-json-shapes") + static class ConcreteGeoJson { + String id; + GeoJsonPolygon shape; + } + + @Data + @Document(collection = "geo-json-shapes") + static class OpenGeoJson { + String id; + GeoJson shape; + } + }