Skip to content

Commit f170758

Browse files
DATAMONGO-1181 - Add Jackson Module for GeoJSON types.
Added GeoJsonModule providing JsonDeserializers for: - GeoJsonPoint - GeoJsonMultiPoint - GeoJsonLineString - GeoJsonMultiLineString - GeoJsonPolygon - GeoJsonMultiPolygon
1 parent 857eb67 commit f170758

File tree

4 files changed

+482
-1
lines changed

4 files changed

+482
-1
lines changed

spring-data-mongodb/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@
144144
<version>${threetenbp}</version>
145145
<optional>true</optional>
146146
</dependency>
147+
148+
<dependency>
149+
<groupId>com.fasterxml.jackson.core</groupId>
150+
<artifactId>jackson-databind</artifactId>
151+
<version>${jackson}</version>
152+
<optional>true</optional>
153+
</dependency>
147154

148155
<dependency>
149156
<groupId>org.slf4j</groupId>
Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
/*
2+
* Copyright 2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.mongodb.core.geo;
17+
18+
import java.io.IOException;
19+
import java.util.ArrayList;
20+
import java.util.Collections;
21+
import java.util.List;
22+
23+
import org.springframework.data.geo.GeoModule;
24+
import org.springframework.data.geo.Point;
25+
26+
import com.fasterxml.jackson.core.JsonParser;
27+
import com.fasterxml.jackson.core.JsonProcessingException;
28+
import com.fasterxml.jackson.databind.DeserializationContext;
29+
import com.fasterxml.jackson.databind.JsonDeserializer;
30+
import com.fasterxml.jackson.databind.JsonNode;
31+
import com.fasterxml.jackson.databind.node.ArrayNode;
32+
33+
/**
34+
* @author Christoph Strobl
35+
* @since 1.7
36+
*/
37+
public class GeoJsonModule extends GeoModule {
38+
39+
public GeoJsonModule() {
40+
super();
41+
42+
addDeserializer(GeoJsonPoint.class, new GeoJsonPointDeserializer());
43+
addDeserializer(GeoJsonMultiPoint.class, new GeoJsonMultiPointDeserializer());
44+
addDeserializer(GeoJsonLineString.class, new GeoJsonLineStringDeserializer());
45+
addDeserializer(GeoJsonMultiLineString.class, new GeoJsonMultiLineStringDeserializer());
46+
addDeserializer(GeoJsonPolygon.class, new GeoJsonPolygonDeserializer());
47+
addDeserializer(GeoJsonMultiPolygon.class, new GeoJsonMultiPolygonDeserializer());
48+
}
49+
50+
/**
51+
* @author Christoph Strobl
52+
* @since 1.7
53+
*/
54+
static abstract class GeoJsonDeserializer<T extends GeoJson<?>> extends JsonDeserializer<T> {
55+
56+
/*
57+
* (non-Javadoc)
58+
* @see com.fasterxml.jackson.databind.JsonDeserializer#deserialize(com.fasterxml.jackson.core.JsonParser, com.fasterxml.jackson.databind.DeserializationContext)
59+
*/
60+
@Override
61+
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
62+
63+
JsonNode node = jp.readValueAsTree();
64+
JsonNode coordinates = node.get("coordinates");
65+
66+
if (coordinates != null && coordinates.isArray()) {
67+
return doDeserialize((ArrayNode) coordinates);
68+
}
69+
return null;
70+
}
71+
72+
/**
73+
* Perform the actual deserialization given the {@literal coordinates} as {@link ArrayNode}.
74+
*
75+
* @param coordinates
76+
* @return
77+
*/
78+
protected abstract T doDeserialize(ArrayNode coordinates);
79+
80+
/**
81+
* Get the {@link GeoJsonPoint} representation of given {@link ArrayNode} assuming {@code node.[0]} represents
82+
* {@literal x - coordinate} and {@code node.[1]} is {@literal y}.
83+
*
84+
* @param node can be {@literal null}.
85+
* @return {@literal null} when given a {@code null} value.
86+
*/
87+
protected GeoJsonPoint toGeoJsonPoint(ArrayNode node) {
88+
89+
if (node == null) {
90+
return null;
91+
}
92+
93+
return new GeoJsonPoint(node.get(0).asDouble(), node.get(1).asDouble());
94+
}
95+
96+
/**
97+
* Get the {@link Point} representation of given {@link ArrayNode} assuming {@code node.[0]} represents
98+
* {@literal x - coordinate} and {@code node.[1]} is {@literal y}.
99+
*
100+
* @param node can be {@literal null}.
101+
* @return {@literal null} when given a {@code null} value.
102+
*/
103+
protected Point toPoint(ArrayNode node) {
104+
105+
if (node == null) {
106+
return null;
107+
}
108+
109+
return new Point(node.get(0).asDouble(), node.get(1).asDouble());
110+
}
111+
112+
/**
113+
* Get the points nested within given {@link ArrayNode}.
114+
*
115+
* @param node can be {@literal null}.
116+
* @return {@literal empty list} when given a {@code null} value.
117+
*/
118+
protected List<Point> toPoints(ArrayNode node) {
119+
120+
if (node == null) {
121+
return Collections.emptyList();
122+
}
123+
124+
List<Point> points = new ArrayList<Point>(node.size());
125+
126+
for (JsonNode coordinatePair : node) {
127+
if (coordinatePair.isArray()) {
128+
points.add(toPoint((ArrayNode) coordinatePair));
129+
}
130+
}
131+
return points;
132+
}
133+
134+
protected GeoJsonLineString toLineString(ArrayNode node) {
135+
return new GeoJsonLineString(toPoints((ArrayNode) node));
136+
}
137+
}
138+
139+
/**
140+
* {@link JsonDeserializer} converting GeoJSON representation of {@literal Point}.
141+
*
142+
* <pre>
143+
* <code>
144+
* { "type": "Point", "coordinates": [10.0, 20.0] }
145+
* </code>
146+
* </pre>
147+
*
148+
* @author Christoph Strobl
149+
* @since 1.7
150+
*/
151+
static class GeoJsonPointDeserializer extends GeoJsonDeserializer<GeoJsonPoint> {
152+
153+
/*
154+
* (non-Javadoc)
155+
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
156+
*/
157+
@Override
158+
protected GeoJsonPoint doDeserialize(ArrayNode coordinates) {
159+
return toGeoJsonPoint(coordinates);
160+
}
161+
}
162+
163+
/**
164+
* {@link JsonDeserializer} converting GeoJSON representation of {@literal LineString}.
165+
*
166+
* <pre>
167+
* <code>
168+
* {
169+
* "type": "LineString",
170+
* "coordinates": [
171+
* [10.0, 20.0], [30.0, 40.0], [50.0, 60.0]
172+
* ]
173+
* }
174+
* </code>
175+
* </pre>
176+
*
177+
* @author Christoph Strobl
178+
* @since 1.7
179+
*/
180+
static class GeoJsonLineStringDeserializer extends GeoJsonDeserializer<GeoJsonLineString> {
181+
182+
/*
183+
* (non-Javadoc)
184+
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
185+
*/
186+
@Override
187+
protected GeoJsonLineString doDeserialize(ArrayNode coordinates) {
188+
return new GeoJsonLineString(toPoints(coordinates));
189+
}
190+
}
191+
192+
/**
193+
* {@link JsonDeserializer} converting GeoJSON representation of {@literal MultiPoint}.
194+
*
195+
* <pre>
196+
* <code>
197+
* {
198+
* "type": "MultiPoint",
199+
* "coordinates": [
200+
* [10.0, 20.0], [30.0, 40.0], [50.0, 60.0]
201+
* ]
202+
* }
203+
* </code>
204+
* </pre>
205+
*
206+
* @author Christoph Strobl
207+
* @since 1.7
208+
*/
209+
static class GeoJsonMultiPointDeserializer extends GeoJsonDeserializer<GeoJsonMultiPoint> {
210+
211+
/*
212+
* (non-Javadoc)
213+
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
214+
*/
215+
@Override
216+
protected GeoJsonMultiPoint doDeserialize(ArrayNode coordinates) {
217+
return new GeoJsonMultiPoint(toPoints(coordinates));
218+
}
219+
}
220+
221+
/**
222+
* {@link JsonDeserializer} converting GeoJSON representation of {@literal MultiLineString}.
223+
*
224+
* <pre>
225+
* <code>
226+
* {
227+
* "type": "MultiLineString",
228+
* "coordinates": [
229+
* [ [10.0, 20.0], [30.0, 40.0] ],
230+
* [ [50.0, 60.0] , [70.0, 80.0] ]
231+
* ]
232+
* }
233+
* </code>
234+
* </pre>
235+
*
236+
* @author Christoph Strobl
237+
* @since 1.7
238+
*/
239+
static class GeoJsonMultiLineStringDeserializer extends GeoJsonDeserializer<GeoJsonMultiLineString> {
240+
241+
/*
242+
* (non-Javadoc)
243+
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
244+
*/
245+
@Override
246+
protected GeoJsonMultiLineString doDeserialize(ArrayNode coordinates) {
247+
248+
List<GeoJsonLineString> lines = new ArrayList<GeoJsonLineString>(coordinates.size());
249+
250+
for (JsonNode lineString : coordinates) {
251+
252+
if (lineString.isArray()) {
253+
lines.add(toLineString((ArrayNode) lineString));
254+
}
255+
}
256+
257+
return new GeoJsonMultiLineString(lines);
258+
}
259+
}
260+
261+
/**
262+
* {@link JsonDeserializer} converting GeoJSON representation of {@literal Polygon}.
263+
*
264+
* <pre>
265+
* <code>
266+
* {
267+
* "type": "Polygon",
268+
* "coordinates": [
269+
* [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]
270+
* ]
271+
* }
272+
* </code>
273+
* </pre>
274+
*
275+
* @author Christoph Strobl
276+
* @since 1.7
277+
*/
278+
static class GeoJsonPolygonDeserializer extends GeoJsonDeserializer<GeoJsonPolygon> {
279+
280+
/*
281+
* (non-Javadoc)
282+
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
283+
*/
284+
@Override
285+
protected GeoJsonPolygon doDeserialize(ArrayNode coordinates) {
286+
287+
for (JsonNode ring : coordinates) {
288+
289+
// currently we do not support holes in polygons.
290+
GeoJsonPolygon polygon = new GeoJsonPolygon(toPoints((ArrayNode) ring));
291+
return polygon;
292+
}
293+
return null;
294+
}
295+
}
296+
297+
/**
298+
* {@link JsonDeserializer} converting GeoJSON representation of {@literal MultiPolygon}.
299+
*
300+
* <pre>
301+
* <code>
302+
* {
303+
* "type": "MultiPolygon",
304+
* "coordinates": [
305+
* [[[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]]],
306+
* [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]],
307+
* [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]]
308+
* ]
309+
* }
310+
* </code>
311+
* </pre>
312+
*
313+
* @author Christoph Strobl
314+
* @since 1.7
315+
*/
316+
static class GeoJsonMultiPolygonDeserializer extends GeoJsonDeserializer<GeoJsonMultiPolygon> {
317+
318+
/*
319+
* (non-Javadoc)
320+
* @see org.springframework.data.mongodb.core.geo.GeoJsonModule.GeoJsonDeserializer#doDeserialize(com.fasterxml.jackson.databind.node.ArrayNode)
321+
*/
322+
@Override
323+
protected GeoJsonMultiPolygon doDeserialize(ArrayNode coordinates) {
324+
325+
List<GeoJsonPolygon> polygones = new ArrayList<GeoJsonPolygon>(coordinates.size());
326+
327+
for (JsonNode polygon : coordinates) {
328+
for (JsonNode ring : (ArrayNode) polygon) {
329+
polygones.add(new GeoJsonPolygon(toPoints((ArrayNode) ring)));
330+
}
331+
}
332+
333+
return new GeoJsonMultiPolygon(polygones);
334+
}
335+
}
336+
}

0 commit comments

Comments
 (0)