OLINGO-1292 adding srid serialization and deserialization to server json
This commit is contained in:
parent
8cbe468c2a
commit
b09dde0b39
|
@ -70,6 +70,7 @@ import org.apache.olingo.commons.api.edm.geo.MultiPoint;
|
|||
import org.apache.olingo.commons.api.edm.geo.MultiPolygon;
|
||||
import org.apache.olingo.commons.api.edm.geo.Point;
|
||||
import org.apache.olingo.commons.api.edm.geo.Polygon;
|
||||
import org.apache.olingo.commons.api.edm.geo.SRID;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.deserializer.DeserializerException;
|
||||
|
@ -769,9 +770,13 @@ public class ODataJsonDeserializer implements ODataDeserializer {
|
|||
final JsonNode topNode = jsonNode.remove(
|
||||
geoDataType.equals(GeospatialCollection.class) ? Constants.JSON_GEOMETRIES : Constants.JSON_COORDINATES);
|
||||
|
||||
// The "crs" member mentioned in some versions of the OData specification is not part of GeoJSON.
|
||||
// It used to be used to specify the coordinate reference system.
|
||||
// TODO: Is it OK to follow RFC 7946 strictly and not allow this element from its obsolete predecessor?
|
||||
SRID srid = null;
|
||||
if (jsonNode.has(Constants.JSON_CRS)) {
|
||||
srid = SRID.valueOf(
|
||||
jsonNode.remove(Constants.JSON_CRS).get(Constants.PROPERTIES).
|
||||
get(Constants.JSON_NAME).asText().split(":")[1]);
|
||||
}
|
||||
|
||||
assertJsonNodeIsEmpty(jsonNode);
|
||||
|
||||
if (topNode != null && topNode.isArray()) {
|
||||
|
@ -779,29 +784,29 @@ public class ODataJsonDeserializer implements ODataDeserializer {
|
|||
Geospatial.Dimension.GEOMETRY :
|
||||
Geospatial.Dimension.GEOGRAPHY;
|
||||
if (geoDataType.equals(Point.class)) {
|
||||
return readGeoPointValue(name, dimension, topNode);
|
||||
return readGeoPointValue(name, dimension, topNode, srid);
|
||||
} else if (geoDataType.equals(MultiPoint.class)) {
|
||||
return new MultiPoint(dimension, null, readGeoPointValues(name, dimension, 0, false, topNode));
|
||||
return new MultiPoint(dimension, srid, readGeoPointValues(name, dimension, 0, false, topNode));
|
||||
} else if (geoDataType.equals(LineString.class)) {
|
||||
// Although a line string with less than two points is not really one, the OData specification says:
|
||||
// "The coordinates member of a LineString can have zero or more positions".
|
||||
// Therefore the required minimal size of the points array currently is zero.
|
||||
return new LineString(dimension, null, readGeoPointValues(name, dimension, 0, false, topNode));
|
||||
return new LineString(dimension, srid, readGeoPointValues(name, dimension, 0, false, topNode));
|
||||
} else if (geoDataType.equals(MultiLineString.class)) {
|
||||
List<LineString> lines = new ArrayList<LineString>();
|
||||
for (final JsonNode element : topNode) {
|
||||
// Line strings can be empty (see above).
|
||||
lines.add(new LineString(dimension, null, readGeoPointValues(name, dimension, 0, false, element)));
|
||||
lines.add(new LineString(dimension, srid, readGeoPointValues(name, dimension, 0, false, element)));
|
||||
}
|
||||
return new MultiLineString(dimension, null, lines);
|
||||
return new MultiLineString(dimension, srid, lines);
|
||||
} else if (geoDataType.equals(Polygon.class)) {
|
||||
return readGeoPolygon(name, dimension, topNode);
|
||||
return readGeoPolygon(name, dimension, topNode, srid);
|
||||
} else if (geoDataType.equals(MultiPolygon.class)) {
|
||||
List<Polygon> polygons = new ArrayList<Polygon>();
|
||||
for (final JsonNode element : topNode) {
|
||||
polygons.add(readGeoPolygon(name, dimension, element));
|
||||
polygons.add(readGeoPolygon(name, dimension, element, null));
|
||||
}
|
||||
return new MultiPolygon(dimension, null, polygons);
|
||||
return new MultiPolygon(dimension, srid, polygons);
|
||||
} else if (geoDataType.equals(GeospatialCollection.class)) {
|
||||
List<Geospatial> elements = new ArrayList<Geospatial>();
|
||||
for (final JsonNode element : topNode) {
|
||||
|
@ -812,7 +817,7 @@ public class ODataJsonDeserializer implements ODataDeserializer {
|
|||
DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, name);
|
||||
}
|
||||
}
|
||||
return new GeospatialCollection(dimension, null, elements);
|
||||
return new GeospatialCollection(dimension, srid, elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -821,11 +826,11 @@ public class ODataJsonDeserializer implements ODataDeserializer {
|
|||
DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, name);
|
||||
}
|
||||
|
||||
private Point readGeoPointValue(final String name, final Geospatial.Dimension dimension, JsonNode node)
|
||||
private Point readGeoPointValue(final String name, final Geospatial.Dimension dimension, JsonNode node, SRID srid)
|
||||
throws DeserializerException, EdmPrimitiveTypeException {
|
||||
if (node.isArray() && (node.size() ==2 || node.size() == 3)
|
||||
&& node.get(0).isNumber() && node.get(1).isNumber() && (node.get(2) == null || node.get(2).isNumber())) {
|
||||
Point point = new Point(dimension, null);
|
||||
Point point = new Point(dimension, srid);
|
||||
point.setX(getDoubleValue(node.get(0).asText()));
|
||||
point.setY(getDoubleValue(node.get(1).asText()));
|
||||
if (node.get(2) != null) {
|
||||
|
@ -855,7 +860,7 @@ public class ODataJsonDeserializer implements ODataDeserializer {
|
|||
if (node.isArray()) {
|
||||
List<Point> points = new ArrayList<Point>();
|
||||
for (final JsonNode element : node) {
|
||||
points.add(readGeoPointValue(name, dimension, element));
|
||||
points.add(readGeoPointValue(name, dimension, element, null));
|
||||
}
|
||||
if (points.size() >= minimalSize
|
||||
&& (!closed || points.get(points.size() - 1).equals(points.get(0)))) {
|
||||
|
@ -866,13 +871,13 @@ public class ODataJsonDeserializer implements ODataDeserializer {
|
|||
DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, name);
|
||||
}
|
||||
|
||||
private Polygon readGeoPolygon(final String name, final Geospatial.Dimension dimension, JsonNode node)
|
||||
private Polygon readGeoPolygon(final String name, final Geospatial.Dimension dimension, JsonNode node, SRID srid)
|
||||
throws DeserializerException, EdmPrimitiveTypeException {
|
||||
// GeoJSON would allow for more than one interior polygon (hole).
|
||||
// But there is no place in the data object to store this information so for now we throw an error.
|
||||
// There could be a more strict verification that the lines describe boundaries and have the correct winding order.
|
||||
if (node.isArray() && (node.size() == 1 || node.size() == 2)) {
|
||||
return new Polygon(dimension, null,
|
||||
return new Polygon(dimension, srid,
|
||||
node.size() > 1 ? readGeoPointValues(name, dimension, 4, true, node.get(1)) : null,
|
||||
readGeoPointValues(name, dimension, 4, true, node.get(0)));
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ import org.apache.olingo.commons.api.edm.geo.MultiPoint;
|
|||
import org.apache.olingo.commons.api.edm.geo.MultiPolygon;
|
||||
import org.apache.olingo.commons.api.edm.geo.Point;
|
||||
import org.apache.olingo.commons.api.edm.geo.Polygon;
|
||||
import org.apache.olingo.commons.api.edm.geo.SRID;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
|
||||
import org.apache.olingo.server.api.ODataServerError;
|
||||
|
@ -920,7 +921,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
writePrimitiveValue(property.getName(), type, property.asPrimitive(),
|
||||
isNullable, maxLength, precision, scale, isUnicode, json);
|
||||
} else if (property.isGeospatial()) {
|
||||
writeGeoValue(property.getName(), type, property.asGeospatial(), isNullable, json);
|
||||
writeGeoValue(property.getName(), type, property.asGeospatial(), isNullable, json, null);
|
||||
} else if (property.isEnum()) {
|
||||
writePrimitiveValue(property.getName(), type, property.asEnum(),
|
||||
isNullable, maxLength, precision, scale, isUnicode, json);
|
||||
|
@ -976,7 +977,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
|
||||
/** Writes a geospatial value following the GeoJSON specification defined in RFC 7946. */
|
||||
protected void writeGeoValue(final String name, final EdmPrimitiveType type, final Geospatial geoValue,
|
||||
final Boolean isNullable, JsonGenerator json)
|
||||
final Boolean isNullable, JsonGenerator json, SRID parentSrid)
|
||||
throws EdmPrimitiveTypeException, IOException, SerializerException {
|
||||
if (geoValue == null) {
|
||||
if (isNullable == null || isNullable) {
|
||||
|
@ -988,10 +989,6 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
if (!type.getDefaultType().isAssignableFrom(geoValue.getClass())) {
|
||||
throw new EdmPrimitiveTypeException("The value type " + geoValue.getClass() + " is not supported.");
|
||||
}
|
||||
if (geoValue.getSrid() != null && geoValue.getSrid().isNotDefault()) {
|
||||
throw new SerializerException("Non-standard SRID not supported!",
|
||||
SerializerException.MessageKeys.WRONG_PROPERTY_VALUE, name, geoValue.toString());
|
||||
}
|
||||
json.writeStartObject();
|
||||
json.writeStringField(Constants.ATTR_TYPE, geoValueTypeToJsonName.get(geoValue.getGeoType()));
|
||||
json.writeFieldName(geoValue.getGeoType() == Geospatial.Type.GEOSPATIALCOLLECTION ?
|
||||
|
@ -1028,14 +1025,28 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
case GEOSPATIALCOLLECTION:
|
||||
for (final Geospatial element : (GeospatialCollection) geoValue) {
|
||||
writeGeoValue(name, EdmPrimitiveTypeFactory.getInstance(element.getEdmPrimitiveTypeKind()),
|
||||
element, isNullable, json);
|
||||
element, isNullable, json, geoValue.getSrid());
|
||||
}
|
||||
break;
|
||||
}
|
||||
json.writeEndArray();
|
||||
|
||||
if (geoValue.getSrid() != null && geoValue.getSrid().isNotDefault()
|
||||
&& (parentSrid == null || !parentSrid.equals(geoValue.getSrid()))) {
|
||||
srid(json, geoValue.getSrid());
|
||||
}
|
||||
json.writeEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
private void srid(final JsonGenerator jgen, final SRID srid) throws IOException {
|
||||
jgen.writeObjectFieldStart(Constants.JSON_CRS);
|
||||
jgen.writeStringField(Constants.ATTR_TYPE, Constants.JSON_NAME);
|
||||
jgen.writeObjectFieldStart(Constants.PROPERTIES);
|
||||
jgen.writeStringField(Constants.JSON_NAME, "EPSG:" + srid.toString());
|
||||
jgen.writeEndObject();
|
||||
jgen.writeEndObject();
|
||||
}
|
||||
|
||||
private void writeGeoPoint(JsonGenerator json, final Point point) throws IOException {
|
||||
json.writeNumber(point.getX());
|
||||
|
|
|
@ -896,12 +896,14 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe
|
|||
public void geoPoint() throws Exception {
|
||||
final EdmEntityType entityType = mockEntityType(EdmPrimitiveTypeKind.GeometryPoint);
|
||||
final String preamble = "{\"" + entityType.getPropertyNames().get(0) + "\":{";
|
||||
final Entity entity = deserialize(preamble + "\"type\":\"Point\",\"coordinates\":[1.25,2.75]}}",
|
||||
final Entity entity = deserialize(preamble + "\"type\":\"Point\",\"coordinates\":[1.25,2.75]," +
|
||||
"\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:42\"}}}}",
|
||||
entityType);
|
||||
assertEquals(1, entity.getProperties().size());
|
||||
assertTrue(entity.getProperties().get(0).getValue() instanceof Point);
|
||||
final Point point = (Point) entity.getProperties().get(0).getValue();
|
||||
assertEquals(Geospatial.Dimension.GEOMETRY, point.getDimension());
|
||||
assertEquals("42", point.getSrid().toString());
|
||||
assertEquals(1.25, point.getX(), 0);
|
||||
assertEquals(2.75, point.getY(), 0);
|
||||
|
||||
|
|
|
@ -18,9 +18,7 @@
|
|||
*/
|
||||
package org.apache.olingo.server.core.serializer.json;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -2306,12 +2304,9 @@ public class ODataJsonSerializerTest {
|
|||
final Entity entity = new Entity()
|
||||
.addProperty(new Property(null, entityType.getPropertyNames().get(0), ValueType.GEOSPATIAL,
|
||||
new Point(Dimension.GEOMETRY, SRID.valueOf("42"))));
|
||||
try {
|
||||
serializerNoMetadata.entity(metadata, entityType, entity, null);
|
||||
fail("Expected exception not thrown.");
|
||||
} catch (final SerializerException e) {
|
||||
assertNotNull(e);
|
||||
}
|
||||
Assert.assertEquals("{\"PropertyGeometryPoint\":{\"type\":\"Point\",\"coordinates\":[0.0,0.0],"
|
||||
+ "\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:42\"}}}}",
|
||||
IOUtils.toString(serializerNoMetadata.entity(metadata, entityType, entity, null).getContent()));
|
||||
}
|
||||
|
||||
private Point createPoint(final double x, final double y) {
|
||||
|
|
|
@ -2312,12 +2312,9 @@ public class ODataJsonSerializerv01Test {
|
|||
final Entity entity = new Entity()
|
||||
.addProperty(new Property(null, entityType.getPropertyNames().get(0), ValueType.GEOSPATIAL,
|
||||
new Point(Dimension.GEOMETRY, SRID.valueOf("42"))));
|
||||
try {
|
||||
serializerNoMetadata.entity(metadata, entityType, entity, null);
|
||||
fail("Expected exception not thrown.");
|
||||
} catch (final SerializerException e) {
|
||||
assertNotNull(e);
|
||||
}
|
||||
Assert.assertEquals("{\"PropertyGeometryPoint\":{\"type\":\"Point\",\"coordinates\":[0.0,0.0],"
|
||||
+ "\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:42\"}}}}",
|
||||
IOUtils.toString(serializerNoMetadata.entity(metadata, entityType, entity, null).getContent()));
|
||||
}
|
||||
|
||||
private Point createPoint(final double x, final double y) {
|
||||
|
|
Loading…
Reference in New Issue