Skip to content

Commit d7b0391

Browse files
Thomas Darimontodrotbohm
authored andcommitted
DATAMONGO-858 - Revised rendering of geo spatial structures.
Switched back to the old style of rendering (as in 1.4.x) of DBObjects when they are used as values in persistent domain objects, adjusted the GeoConverters accordingly. In order to render geo structures correctly when they are used within a query we now wrap them in a GeoCommand that triggers a different Shape rendering. We now render the metric that was used in the Distance definition of the radius of a Circle or Sphere.
1 parent ed55d48 commit d7b0391

File tree

8 files changed

+417
-197
lines changed

8 files changed

+417
-197
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/GeoConverters.java

Lines changed: 231 additions & 93 deletions
Large diffs are not rendered by default.

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Criteria.java

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,8 @@
2525
import java.util.regex.Pattern;
2626

2727
import org.bson.BSON;
28-
import org.springframework.data.geo.Box;
2928
import org.springframework.data.geo.Circle;
3029
import org.springframework.data.geo.Point;
31-
import org.springframework.data.geo.Polygon;
3230
import org.springframework.data.geo.Shape;
3331
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
3432
import org.springframework.data.mongodb.core.geo.Sphere;
@@ -386,7 +384,7 @@ private Pattern toPattern(String regex, String options) {
386384
*/
387385
public Criteria withinSphere(Circle circle) {
388386
Assert.notNull(circle);
389-
criteria.put("$within", wrapInCommand(new Sphere(circle)));
387+
criteria.put("$within", new GeoCommand(new Sphere(circle)));
390388
return this;
391389
}
392390

@@ -400,7 +398,7 @@ public Criteria withinSphere(Circle circle) {
400398
@Deprecated
401399
public Criteria withinSphere(org.springframework.data.mongodb.core.geo.Circle circle) {
402400
Assert.notNull(circle);
403-
criteria.put("$within", wrapInCommand(new Sphere(circle)));
401+
criteria.put("$within", new GeoCommand(new Sphere(circle)));
404402
return this;
405403
}
406404

@@ -414,7 +412,7 @@ public Criteria withinSphere(org.springframework.data.mongodb.core.geo.Circle ci
414412
public Criteria within(Shape shape) {
415413

416414
Assert.notNull(shape);
417-
criteria.put("$within", wrapInCommand(shape));
415+
criteria.put("$within", new GeoCommand(shape));
418416
return this;
419417
}
420418

@@ -660,43 +658,6 @@ private boolean isEqual(Object left, Object right) {
660658
return ObjectUtils.nullSafeEquals(left, right);
661659
}
662660

663-
/**
664-
* Wraps the given {@link Shape} in an appropriate MongoDB command.
665-
*
666-
* @param shape must not be {@literal null}.
667-
* @return
668-
*/
669-
private DBObject wrapInCommand(Shape shape) {
670-
671-
Assert.notNull(shape, "Shape must not be null!");
672-
673-
return new BasicDBObject(getCommand(shape), shape);
674-
}
675-
676-
/**
677-
* Returns the MongoDB command for the given {@link Shape}.
678-
*
679-
* @param shape must not be {@literal null}.
680-
* @return
681-
*/
682-
@SuppressWarnings("deprecation")
683-
private String getCommand(Shape shape) {
684-
685-
Assert.notNull(shape, "Shape must not be null!");
686-
687-
if (shape instanceof Box) {
688-
return org.springframework.data.mongodb.core.geo.Box.COMMAND;
689-
} else if (shape instanceof Circle || shape instanceof org.springframework.data.mongodb.core.geo.Circle) {
690-
return org.springframework.data.mongodb.core.geo.Circle.COMMAND;
691-
} else if (shape instanceof Polygon) {
692-
return org.springframework.data.mongodb.core.geo.Polygon.COMMAND;
693-
} else if (shape instanceof Sphere) {
694-
return org.springframework.data.mongodb.core.geo.Sphere.COMMAND;
695-
}
696-
697-
throw new IllegalArgumentException("Unknown shape: " + shape);
698-
}
699-
700661
/*
701662
* (non-Javadoc)
702663
* @see java.lang.Object#hashCode()
Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package org.springframework.data.mongodb.core.convert;
16+
package org.springframework.data.mongodb.core.query;
1717

1818
import org.springframework.data.geo.Box;
1919
import org.springframework.data.geo.Circle;
@@ -22,27 +22,42 @@
2222
import org.springframework.data.mongodb.core.geo.Sphere;
2323
import org.springframework.util.Assert;
2424

25-
import com.mongodb.BasicDBObject;
26-
import com.mongodb.DBObject;
27-
2825
/**
26+
* Wrapper around a {@link Shape} to allow appropriate query rendering.
27+
*
2928
* @author Thomas Darimont
29+
* @since 1.5
3030
*/
31-
public enum GeoCommandUtils {
31+
public class GeoCommand {
3232

33-
INSTANCE;
33+
private final Shape shape;
34+
private final String command;
3435

3536
/**
36-
* Wraps the given {@link Shape} in an appropriate MongoDB command.
37+
* Creates a new {@link GeoCommand}.
3738
*
3839
* @param shape must not be {@literal null}.
39-
* @return
4040
*/
41-
public DBObject wrapInCommand(Shape shape) {
41+
public GeoCommand(Shape shape) {
4242

4343
Assert.notNull(shape, "Shape must not be null!");
4444

45-
return new BasicDBObject(getCommand(shape), shape);
45+
this.shape = shape;
46+
this.command = getCommand(shape);
47+
}
48+
49+
/**
50+
* @return the shape
51+
*/
52+
public Shape getShape() {
53+
return shape;
54+
}
55+
56+
/**
57+
* @return the command
58+
*/
59+
public String getCommand() {
60+
return command;
4661
}
4762

4863
/**
@@ -51,6 +66,7 @@ public DBObject wrapInCommand(Shape shape) {
5166
* @param shape must not be {@literal null}.
5267
* @return
5368
*/
69+
@SuppressWarnings("deprecation")
5470
private String getCommand(Shape shape) {
5571

5672
Assert.notNull(shape, "Shape must not be null!");

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/GeoConvertersUnitTests.java

Lines changed: 71 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,33 +18,38 @@
1818
import static org.hamcrest.CoreMatchers.*;
1919
import static org.junit.Assert.*;
2020

21-
import java.util.List;
21+
import java.util.Arrays;
2222

2323
import org.junit.Test;
2424
import org.springframework.data.geo.Box;
2525
import org.springframework.data.geo.Circle;
26+
import org.springframework.data.geo.Distance;
27+
import org.springframework.data.geo.Metrics;
2628
import org.springframework.data.geo.Point;
2729
import org.springframework.data.geo.Polygon;
2830
import org.springframework.data.mongodb.core.convert.GeoConverters.BoxToDbObjectConverter;
2931
import org.springframework.data.mongodb.core.convert.GeoConverters.CircleToDbObjectConverter;
3032
import org.springframework.data.mongodb.core.convert.GeoConverters.DbObjectToBoxConverter;
3133
import org.springframework.data.mongodb.core.convert.GeoConverters.DbObjectToCircleConverter;
3234
import org.springframework.data.mongodb.core.convert.GeoConverters.DbObjectToLegacyCircleConverter;
35+
import org.springframework.data.mongodb.core.convert.GeoConverters.DbObjectToPointConverter;
3336
import org.springframework.data.mongodb.core.convert.GeoConverters.DbObjectToPolygonConverter;
3437
import org.springframework.data.mongodb.core.convert.GeoConverters.DbObjectToSphereConverter;
38+
import org.springframework.data.mongodb.core.convert.GeoConverters.GeoCommandToDbObjectConverter;
3539
import org.springframework.data.mongodb.core.convert.GeoConverters.LegacyCircleToDbObjectConverter;
36-
import org.springframework.data.mongodb.core.convert.GeoConverters.ListToPointConverter;
37-
import org.springframework.data.mongodb.core.convert.GeoConverters.PointToListConverter;
40+
import org.springframework.data.mongodb.core.convert.GeoConverters.PointToDbObjectConverter;
3841
import org.springframework.data.mongodb.core.convert.GeoConverters.PolygonToDbObjectConverter;
3942
import org.springframework.data.mongodb.core.convert.GeoConverters.SphereToDbObjectConverter;
4043
import org.springframework.data.mongodb.core.geo.Sphere;
44+
import org.springframework.data.mongodb.core.query.GeoCommand;
4145

42-
import com.mongodb.BasicDBList;
46+
import com.mongodb.DBObject;
4347

4448
/**
4549
* Unit tests for {@link GeoConverters}.
4650
*
4751
* @author Thomas Darimont
52+
* @author Oliver Gierke
4853
* @since 1.5
4954
*/
5055
@SuppressWarnings("deprecation")
@@ -58,7 +63,7 @@ public void convertsBoxToDbObjectAndBackCorrectly() {
5863

5964
Box box = new Box(new Point(1, 2), new Point(3, 4));
6065

61-
BasicDBList dbo = BoxToDbObjectConverter.INSTANCE.convert(box);
66+
DBObject dbo = BoxToDbObjectConverter.INSTANCE.convert(box);
6267
Box result = DbObjectToBoxConverter.INSTANCE.convert(dbo);
6368

6469
assertThat(result, is(box));
@@ -69,16 +74,32 @@ public void convertsBoxToDbObjectAndBackCorrectly() {
6974
* @see DATAMONGO-858
7075
*/
7176
@Test
72-
public void convertsCircleToDbObjectAndBackCorrectly() {
77+
public void convertsCircleToDbObjectAndBackCorrectlyNeutralDistance() {
7378

7479
Circle circle = new Circle(new Point(1, 2), 3);
7580

76-
BasicDBList dbo = CircleToDbObjectConverter.INSTANCE.convert(circle);
81+
DBObject dbo = CircleToDbObjectConverter.INSTANCE.convert(circle);
7782
Circle result = DbObjectToCircleConverter.INSTANCE.convert(dbo);
7883

7984
assertThat(result, is(circle));
8085
}
8186

87+
/**
88+
* @see DATAMONGO-858
89+
*/
90+
@Test
91+
public void convertsCircleToDbObjectAndBackCorrectlyMilesDistance() {
92+
93+
Distance radius = new Distance(3, Metrics.MILES);
94+
Circle circle = new Circle(new Point(1, 2), radius);
95+
96+
DBObject dbo = CircleToDbObjectConverter.INSTANCE.convert(circle);
97+
Circle result = DbObjectToCircleConverter.INSTANCE.convert(dbo);
98+
99+
assertThat(result, is(circle));
100+
assertThat(result.getRadius(), is(radius));
101+
}
102+
82103
/**
83104
* @see DATAMONGO-858
84105
*/
@@ -88,7 +109,7 @@ public void convertsLegacyCircleToDbObjectAndBackCorrectly() {
88109
org.springframework.data.mongodb.core.geo.Circle circle = new org.springframework.data.mongodb.core.geo.Circle(
89110
new Point(1, 2), 3);
90111

91-
BasicDBList dbo = LegacyCircleToDbObjectConverter.INSTANCE.convert(circle);
112+
DBObject dbo = LegacyCircleToDbObjectConverter.INSTANCE.convert(circle);
92113
org.springframework.data.mongodb.core.geo.Circle result = DbObjectToLegacyCircleConverter.INSTANCE.convert(dbo);
93114

94115
assertThat(result, is(circle));
@@ -102,7 +123,7 @@ public void convertsPolygonToDbObjectAndBackCorrectly() {
102123

103124
Polygon polygon = new Polygon(new Point(1, 2), new Point(2, 3), new Point(3, 4), new Point(5, 6));
104125

105-
BasicDBList dbo = PolygonToDbObjectConverter.INSTANCE.convert(polygon);
126+
DBObject dbo = PolygonToDbObjectConverter.INSTANCE.convert(polygon);
106127
Polygon result = DbObjectToPolygonConverter.INSTANCE.convert(dbo);
107128

108129
assertThat(result, is(polygon));
@@ -113,14 +134,31 @@ public void convertsPolygonToDbObjectAndBackCorrectly() {
113134
* @see DATAMONGO-858
114135
*/
115136
@Test
116-
public void convertsSphereToDbObjectAndBackCorrectly() {
137+
public void convertsSphereToDbObjectAndBackCorrectlyWithNeutralDistance() {
117138

118139
Sphere sphere = new Sphere(new Point(1, 2), 3);
119140

120-
BasicDBList dbo = SphereToDbObjectConverter.INSTANCE.convert(sphere);
141+
DBObject dbo = SphereToDbObjectConverter.INSTANCE.convert(sphere);
142+
Sphere result = DbObjectToSphereConverter.INSTANCE.convert(dbo);
143+
144+
assertThat(result, is(sphere));
145+
assertThat(result.getClass().equals(org.springframework.data.mongodb.core.geo.Sphere.class), is(true));
146+
}
147+
148+
/**
149+
* @see DATAMONGO-858
150+
*/
151+
@Test
152+
public void convertsSphereToDbObjectAndBackCorrectlyWithKilometerDistance() {
153+
154+
Distance radius = new Distance(3, Metrics.KILOMETERS);
155+
Sphere sphere = new Sphere(new Point(1, 2), radius);
156+
157+
DBObject dbo = SphereToDbObjectConverter.INSTANCE.convert(sphere);
121158
Sphere result = DbObjectToSphereConverter.INSTANCE.convert(dbo);
122159

123160
assertThat(result, is(sphere));
161+
assertThat(result.getRadius(), is(radius));
124162
assertThat(result.getClass().equals(org.springframework.data.mongodb.core.geo.Sphere.class), is(true));
125163
}
126164

@@ -132,10 +170,30 @@ public void convertsPointToListAndBackCorrectly() {
132170

133171
Point point = new Point(1, 2);
134172

135-
List<Double> list = PointToListConverter.INSTANCE.convert(point);
136-
Point result = ListToPointConverter.INSTANCE.convert(list);
173+
DBObject dbo = PointToDbObjectConverter.INSTANCE.convert(point);
174+
Point result = DbObjectToPointConverter.INSTANCE.convert(dbo);
137175

138176
assertThat(result, is(point));
139177
assertThat(result.getClass().equals(org.springframework.data.mongodb.core.geo.Point.class), is(true));
140178
}
179+
180+
/**
181+
* @see DATAMONGO-858
182+
*/
183+
@Test
184+
@SuppressWarnings("unchecked")
185+
public void convertsGeoCommandToDbObjectCorrectly() {
186+
187+
Box box = new Box(new double[] { 1, 2 }, new double[] { 3, 4 });
188+
GeoCommand cmd = new GeoCommand(box);
189+
190+
DBObject dbo = GeoCommandToDbObjectConverter.INSTANCE.convert(cmd);
191+
192+
assertThat(dbo, is(notNullValue()));
193+
194+
DBObject boxObject = (DBObject) dbo.get("$box");
195+
196+
assertThat(boxObject,
197+
is((Object) Arrays.asList(GeoConverters.toList(box.getFirst()), GeoConverters.toList(box.getSecond()))));
198+
}
141199
}

0 commit comments

Comments
 (0)