Skip to content

Commit

Permalink
Serialize GeoJson with an optional BBOX element.
Browse files Browse the repository at this point in the history
Introduces settings to turn on the serialization of
a 'bbox' element for Feature and FeatureCollection objects.
  • Loading branch information
maesenka committed Aug 12, 2022
1 parent 0dac0d2 commit a23a681
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 35 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.geolatte.geom.json;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
Expand All @@ -15,16 +14,17 @@
import java.util.Iterator;
import java.util.List;

public class FeatureCollectionDeserializer extends JsonDeserializer<FeatureCollection> {

@SuppressWarnings("rawtypes")
public class FeatureCollectionDeserializer extends JsonDeserializer<FeatureCollection> {
final private FeatureDeserializer fDeserializer;
public FeatureCollectionDeserializer(CoordinateReferenceSystem<?> defaultCrs, Settings settings) {
this.fDeserializer = new FeatureDeserializer(defaultCrs, settings);
}

@Override
@SuppressWarnings("unchecked")
public FeatureCollection<?, ?> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
public FeatureCollection<?, ?> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
ObjectCodec oc = jsonParser.getCodec();
JsonNode root = oc.readTree(jsonParser);
JsonNode featureNds = root.get("features");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.geolatte.geom.json;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.geolatte.geom.Box;
import org.geolatte.geom.Feature;
import org.geolatte.geom.FeatureCollection;
import org.geolatte.geom.Position;

import java.io.IOException;

public class FeatureCollectionSerializer<P extends Position, ID> extends JsonSerializer<FeatureCollection<P, ID>> {

private final Settings settings;

FeatureCollectionSerializer(Settings settings) {
this.settings = settings;
}

@Override
public void serialize(FeatureCollection<P, ID> featureColl, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {
gen.writeStartObject();
gen.writeStringField("type", FeatureCollection.TYPE);
Box<?> box = featureColl.getBbox();
if (box != null && !box.isEmpty() && settings.isSet(Setting.SERIALIZE_FEATURE_COLLECTION_BBOX)) {
gen.writeFieldName("bbox");
gen.writeObject(featureColl.getBbox());
}
gen.writeArrayFieldStart("features");
for (Feature<?, ?> f : featureColl.getFeatures()) {
gen.writeObject(f);
}
gen.writeEndArray();
gen.writeEndObject();

}
}
39 changes: 39 additions & 0 deletions json/src/main/java/org/geolatte/geom/json/FeatureSerializer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.geolatte.geom.json;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.geolatte.geom.Box;
import org.geolatte.geom.Feature;
import org.geolatte.geom.Position;

import java.io.IOException;

public class FeatureSerializer<P extends Position, ID> extends JsonSerializer<Feature<P, ID>> {

private final Settings settings;

public FeatureSerializer(Settings settings) {
this.settings = settings;
}

@Override
public void serialize(Feature<P, ID> feature, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {
gen.writeStartObject();
gen.writeStringField("type", Feature.TYPE);
if (feature.getId() != null) {
gen.writeFieldName("id");
gen.writeObject(feature.getId());
}
Box<?> box = feature.getBbox();
if (box != null && !box.isEmpty() && settings.isSet(Setting.SERIALIZE_FEATURE_BBOX)) {
gen.writeFieldName("bbox");
gen.writeObject(box);
}
gen.writeFieldName("geometry");
gen.writeObject(feature.getGeometry());
gen.writeFieldName("properties");
gen.writeObject(feature.getProperties());
gen.writeEndObject();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.geolatte.geom.json;

import com.fasterxml.jackson.annotation.JsonInclude;
import org.geolatte.geom.Box;
import org.geolatte.geom.Feature;
import org.geolatte.geom.FeatureCollection;
Expand All @@ -11,8 +10,6 @@
import java.util.List;
import java.util.Objects;

import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY;

public class GeoJsonFeatureCollection<P extends Position, ID> implements FeatureCollection<P, ID> {
private final List<Feature<P, ID>> features;

Expand All @@ -34,7 +31,6 @@ public List<Feature<P, ID>> getFeatures() {
}

@Override
@JsonInclude(NON_EMPTY)
public Box<P> getBbox() {
Box<P> bbox = null;
for (Feature<P, ID> feature : features) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@
* <p>
* Created by Karel Maesen, Geovise BVBA on 08/09/17.
*/
@SuppressWarnings("rawtypes")
public class GeolatteGeomModule extends SimpleModule {


private final Settings settings = new Settings();

private final Map<Class, JsonDeserializer> dezers = new HashMap<>();

private GeometrySerializer geometrySerializer;
private CrsSerializer crsSerializer;
private BoxSerializer boxSerializer;
private final GeometrySerializer geometrySerializer;
private final CrsSerializer crsSerializer;

public GeolatteGeomModule() {
this(WGS84);
Expand All @@ -35,15 +35,19 @@ public GeolatteGeomModule() {
@SuppressWarnings("unchecked")
public <P extends Position> GeolatteGeomModule(CoordinateReferenceSystem<P> defaultCrs) {

super("GeolatteGeomModule", new Version(1, 8, 0, "", "org.geolatte", "geolatte-json"));
super("GeolatteGeomModule", new Version(1, 9, 0, "", "org.geolatte", "geolatte-json"));

geometrySerializer = new GeometrySerializer(settings);
FeatureSerializer featureSerializer = new FeatureSerializer(settings);
addSerializer(Feature.class, featureSerializer);
FeatureCollectionSerializer featureCollectionSerializer = new FeatureCollectionSerializer(settings);
GeometryDeserializer parser = new GeometryDeserializer(defaultCrs, settings);
addSerializer(Geometry.class, geometrySerializer); //use raw to get this compiled
crsSerializer = new CrsSerializer<>(defaultCrs, settings);
addSerializer(CoordinateReferenceSystem.class, crsSerializer);
boxSerializer = new BoxSerializer<>();
BoxSerializer boxSerializer = new BoxSerializer<>();
addSerializer(Box.class, boxSerializer);
addSerializer(FeatureCollection.class, featureCollectionSerializer);
dezers.put(Geometry.class, parser);
dezers.put(Point.class, parser);
dezers.put(LineString.class, parser);
Expand Down
12 changes: 11 additions & 1 deletion json/src/main/java/org/geolatte/geom/json/Setting.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,17 @@ public enum Setting {
/**
* Serialize the CRS as a URN, rather than the traditional AUTH:CODE format.
*/
SERIALIZE_CRS_AS_URN(false);
SERIALIZE_CRS_AS_URN(false),

/**
* Serialized a BBOX for a FeatureCollection
*/
SERIALIZE_FEATURE_COLLECTION_BBOX(false),

/**
* Serialize a BBOX for a feature
*/
SERIALIZE_FEATURE_BBOX(false);

private boolean setByDefault;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.geolatte.geom.json;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.geolatte.geom.FeatureCollection;
import org.geolatte.geom.G2D;

import static org.geolatte.geom.builder.DSL.*;
import static org.geolatte.geom.crs.CoordinateReferenceSystems.WGS84;
Expand All @@ -19,17 +19,9 @@ public class FeatureCollectionSerializationTest extends GeoJsonTest {

@Test
public void testSerialize() throws IOException {
Map<String, Object> map1 = new HashMap<>();
map1.put("prop0", "value0");
Map<String, Object> map2 = new HashMap<>();
map2.put("prop1", 0.0d);
map2.put("prop0", "value0");
FeatureCollection<?, ?> fc = new GeoJsonFeatureCollection<>(
new GeoJsonFeature<G2D, String>(point(WGS84, g(102, 0.5)), "1", map1),
new GeoJsonFeature<G2D, String>(linestring(WGS84, g(102, 0), g(103, 1),
g(104, 0), g(105, 1)), "2", map2));
FeatureCollection<?, ?> fc = mkExample();
String rec = mapper.writeValueAsString(fc);
assertEquals(featureCollection, rec) ;
assertEquals(featureCollectionNoBbox, rec) ;
}

@Test
Expand All @@ -38,4 +30,23 @@ public void testEmptySerialize() throws IOException {
String rec = mapper.writeValueAsString(fc);
assertEquals(emptyFeatureCollection, rec) ;
}

@Test
public void testWithBbox() throws IOException {
ObjectMapper mapper = createMapper(Setting.SERIALIZE_FEATURE_COLLECTION_BBOX, true);
String rec = mapper.writeValueAsString(mkExample());
assertEquals(featureCollection, rec);
}

private static FeatureCollection<?, ?> mkExample() {
Map<String, Object> map1 = new HashMap<>();
map1.put("prop0", "value0");
Map<String, Object> map2 = new HashMap<>();
map2.put("prop1", 0.0d);
map2.put("prop0", "value0");
return new GeoJsonFeatureCollection<>(
new GeoJsonFeature<>(point(WGS84, g(102, 0.5)), "1", map1),
new GeoJsonFeature<>(linestring(WGS84, g(102, 0), g(103, 1),
g(104, 0), g(105, 1)), "2", map2));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@
import static org.geolatte.geom.builder.DSL.linestring;
import static org.geolatte.geom.builder.DSL.point;
import static org.geolatte.geom.crs.CoordinateReferenceSystems.WGS84;
import static org.geolatte.geom.json.GeoJsonStrings.feature;
import static org.geolatte.geom.json.GeoJsonStrings.featureEmptyPolygon;
import static org.geolatte.geom.json.GeoJsonStrings.featureNullGeometry;
import static org.geolatte.geom.json.GeoJsonStrings.featureWithLineString;
import static org.geolatte.geom.json.GeoJsonStrings.*;
import static org.geolatte.geom.json.Setting.SUPPRESS_CRS_SERIALIZATION;
import static org.junit.Assert.assertEquals;

Expand All @@ -34,9 +31,24 @@ public void testSerialize() throws IOException {
assertEquals(feature, rec);
}

@Test
public void testSerializeWithBBox() throws IOException {
ObjectMapper mapper = createMapper(Setting.SERIALIZE_FEATURE_BBOX, true);
Map<String, Object> map = new HashMap<>();
map.put("a", 1);
Feature<?, ?> f = new GeoJsonFeature<>(point(WGS84, g(1, 2)), "1", map);
String rec = mapper.writeValueAsString(f);
assertEquals(featureWithBBox, rec);
}



@Test
public void testSerializeLineStringFeature() throws IOException {
ObjectMapper mapper = createMapper(SUPPRESS_CRS_SERIALIZATION, true);
Map<Setting, Boolean> settingsMap = new HashMap<>();
settingsMap.put(SUPPRESS_CRS_SERIALIZATION, true);
settingsMap.put(Setting.SERIALIZE_FEATURE_BBOX, true);
ObjectMapper mapper = createMapper(settingsMap);
Map<String, Object> map = new HashMap<>();
map.put("a", 1);
Feature<?, ?> f = new GeoJsonFeature<>(linestring(WGS84, g(1, 2), g(3, 4)), "1", map);
Expand Down
14 changes: 8 additions & 6 deletions json/src/test/java/org/geolatte/geom/json/GeoJsonStrings.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,15 @@ public class GeoJsonStrings {
static String geometryCollectionWithCrs3D= "{\"type\":\"GeometryCollection\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:31370\"}},\"geometries\":[{\"type\":\"LineString\",\"coordinates\":[[1.0,1.0,1.0],[1.0,2.0,3.0]]},{\"type\":\"Point\",\"coordinates\":[5.0,6.0,7.0]}]}";

// Features
static String feature = "{\"geometry\":{\"type\":\"Point\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}},\"coordinates\":[1.0,2.0]},\"id\":\"1\",\"properties\":{\"a\":1},\"type\":\"Feature\"}";
static String featureWithLineString = "{\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[1.0,2.0],[3.0,4.0]]},\"id\":\"1\",\"properties\":{\"a\":1},\"bbox\":[1.0,2.0,3.0,4.0],\"type\":\"Feature\"}";
static String feature = "{\"type\":\"Feature\",\"id\":\"1\",\"geometry\":{\"type\":\"Point\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}},\"coordinates\":[1.0,2.0]},\"properties\":{\"a\":1}}";
static String featureWithBBox = "{\"type\":\"Feature\",\"id\":\"1\",\"bbox\":[1.0,2.0,1.0,2.0],\"geometry\":{\"type\":\"Point\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}},\"coordinates\":[1.0,2.0]},\"properties\":{\"a\":1}}";
static String featureWithLineString = "{\"type\":\"Feature\",\"id\":\"1\",\"bbox\":[1.0,2.0,3.0,4.0],\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[1.0,2.0],[3.0,4.0]]},\"properties\":{\"a\":1}}";


static String featureIntId = "{\"type\" : \"Feature\", \"id\": 1, \"geometry\": {\"type\":\"Point\",\"coordinates\":[1.0,2.0]}, " +
"\"properties\": { \"a\" : 1 }}";
static String featureNullGeometry = "{\"geometry\":null,\"id\":\"1\",\"properties\":{\"a\":1},\"type\":\"Feature\"}";
static String featureEmptyPolygon = "{\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[]},\"id\":\"1\",\"properties\":{\"a\":1},\"type\":\"Feature\"}";
static String featureNullGeometry = "{\"type\":\"Feature\",\"id\":\"1\",\"geometry\":null,\"properties\":{\"a\":1}}";
static String featureEmptyPolygon = "{\"type\":\"Feature\",\"id\":\"1\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[]},\"properties\":{\"a\":1}}";

// crs
static String crswgs84 = "{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}";
Expand All @@ -71,6 +72,7 @@ public class GeoJsonStrings {

//FeatureCollection

static String featureCollection = "{\"features\":[{\"geometry\":{\"type\":\"Point\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}},\"coordinates\":[102.0,0.5]},\"id\":\"1\",\"properties\":{\"prop0\":\"value0\"},\"type\":\"Feature\"},{\"geometry\":{\"type\":\"LineString\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}},\"coordinates\":[[102.0,0.0],[103.0,1.0],[104.0,0.0],[105.0,1.0]]},\"id\":\"2\",\"properties\":{\"prop1\":0.0,\"prop0\":\"value0\"},\"bbox\":[102.0,0.0,105.0,1.0],\"type\":\"Feature\"}],\"bbox\":[102.0,0.0,105.0,1.0],\"type\":\"FeatureCollection\"}";
static String emptyFeatureCollection = "{\"features\":[],\"type\":\"FeatureCollection\"}";
static String featureCollection = "{\"type\":\"FeatureCollection\",\"bbox\":[102.0,0.0,105.0,1.0],\"features\":[{\"type\":\"Feature\",\"id\":\"1\",\"geometry\":{\"type\":\"Point\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}},\"coordinates\":[102.0,0.5]},\"properties\":{\"prop0\":\"value0\"}},{\"type\":\"Feature\",\"id\":\"2\",\"geometry\":{\"type\":\"LineString\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}},\"coordinates\":[[102.0,0.0],[103.0,1.0],[104.0,0.0],[105.0,1.0]]},\"properties\":{\"prop1\":0.0,\"prop0\":\"value0\"}}]}";
static String featureCollectionNoBbox = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":\"1\",\"geometry\":{\"type\":\"Point\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}},\"coordinates\":[102.0,0.5]},\"properties\":{\"prop0\":\"value0\"}},{\"type\":\"Feature\",\"id\":\"2\",\"geometry\":{\"type\":\"LineString\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}},\"coordinates\":[[102.0,0.0],[103.0,1.0],[104.0,0.0],[105.0,1.0]]},\"properties\":{\"prop1\":0.0,\"prop0\":\"value0\"}}]}";
static String emptyFeatureCollection = "{\"type\":\"FeatureCollection\",\"features\":[]}";
}

0 comments on commit a23a681

Please sign in to comment.