diff --git a/src/main/java/org/elasticsearch/common/geo/builders/ShapeBuilder.java b/src/main/java/org/elasticsearch/common/geo/builders/ShapeBuilder.java index 04bdbcca5b4..f07f6554cc9 100644 --- a/src/main/java/org/elasticsearch/common/geo/builders/ShapeBuilder.java +++ b/src/main/java/org/elasticsearch/common/geo/builders/ShapeBuilder.java @@ -346,6 +346,10 @@ public abstract class ShapeBuilder implements ToXContent { this.coordinate = null; } + protected boolean isEmpty() { + return (coordinate == null && (children == null || children.isEmpty())); + } + @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { if (children == null) { @@ -607,7 +611,19 @@ public abstract class ShapeBuilder implements ToXContent { } } + protected static void validatePointNode(CoordinateNode node) { + if (node.isEmpty()) { + throw new ElasticsearchParseException("Invalid number of points (0) provided when expecting a single coordinate " + + "([lat, lng])"); + } else if (node.coordinate == null) { + if (node.children.isEmpty() == false) { + throw new ElasticsearchParseException("multipoint data provided when single point data expected."); + } + } + } + protected static PointBuilder parsePoint(CoordinateNode node) { + validatePointNode(node); return newPoint(node.coordinate); } @@ -619,7 +635,24 @@ public abstract class ShapeBuilder implements ToXContent { return newEnvelope().topLeft(coordinates.children.get(0).coordinate).bottomRight(coordinates.children.get(1).coordinate); } + protected static void validateMultiPointNode(CoordinateNode coordinates) { + if (coordinates.children == null || coordinates.children.isEmpty()) { + if (coordinates.coordinate != null) { + throw new ElasticsearchParseException("single coordinate found when expecting an array of " + + "coordinates. change type to point or change data to an array of >0 coordinates"); + } + throw new ElasticsearchParseException("No data provided for multipoint object when expecting " + + ">0 points (e.g., [[lat, lng]] or [[lat, lng], ...])"); + } else { + for (CoordinateNode point : coordinates.children) { + validatePointNode(point); + } + } + } + protected static MultiPointBuilder parseMultiPoint(CoordinateNode coordinates) { + validateMultiPointNode(coordinates); + MultiPointBuilder points = new MultiPointBuilder(); for (CoordinateNode node : coordinates.children) { points.point(node.coordinate); @@ -671,6 +704,11 @@ public abstract class ShapeBuilder implements ToXContent { } protected static PolygonBuilder parsePolygon(CoordinateNode coordinates) { + if (coordinates.children == null || coordinates.children.isEmpty()) { + throw new ElasticsearchParseException("Invalid LinearRing provided for type polygon. Linear ring must be an array of " + + "coordinates"); + } + LineStringBuilder shell = parseLinearRing(coordinates.children.get(0)); PolygonBuilder polygon = new PolygonBuilder(shell.points); for (int i = 1; i < coordinates.children.size(); i++) { diff --git a/src/test/java/org/elasticsearch/common/geo/GeoJSONShapeParserTests.java b/src/test/java/org/elasticsearch/common/geo/GeoJSONShapeParserTests.java index e3b4eff2ecd..77ced146e01 100644 --- a/src/test/java/org/elasticsearch/common/geo/GeoJSONShapeParserTests.java +++ b/src/test/java/org/elasticsearch/common/geo/GeoJSONShapeParserTests.java @@ -157,6 +157,58 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase { assertGeometryEquals(jtsGeom(expected), polygonGeoJson); } + @Test + public void testParse_invalidPoint() throws IOException { + // test case 1: create an invalid point object with multipoint data format + String invalidPoint1 = XContentFactory.jsonBuilder().startObject().field("type", "point") + .startArray("coordinates") + .startArray().value(-74.011).value(40.753).endArray() + .endArray() + .endObject().string(); + XContentParser parser = JsonXContent.jsonXContent.createParser(invalidPoint1); + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + + // test case 2: create an invalid point object with an empty number of coordinates + String invalidPoint2 = XContentFactory.jsonBuilder().startObject().field("type", "point") + .startArray("coordinates") + .endArray() + .endObject().string(); + parser = JsonXContent.jsonXContent.createParser(invalidPoint2); + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } + + @Test + public void testParse_invalidMultipoint() throws IOException { + // test case 1: create an invalid multipoint object with single coordinate + String invalidMultipoint1 = XContentFactory.jsonBuilder().startObject().field("type", "multipoint") + .startArray("coordinates").value(-74.011).value(40.753).endArray() + .endObject().string(); + XContentParser parser = JsonXContent.jsonXContent.createParser(invalidMultipoint1); + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + + // test case 2: create an invalid multipoint object with null coordinate + String invalidMultipoint2 = XContentFactory.jsonBuilder().startObject().field("type", "multipoint") + .startArray("coordinates") + .endArray() + .endObject().string(); + parser = JsonXContent.jsonXContent.createParser(invalidMultipoint2); + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + + // test case 3: create a valid formatted multipoint object with invalid number (0) of coordinates + String invalidMultipoint3 = XContentFactory.jsonBuilder().startObject().field("type", "multipoint") + .startArray("coordinates") + .startArray().endArray() + .endArray() + .endObject().string(); + parser = JsonXContent.jsonXContent.createParser(invalidMultipoint3); + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); + } + @Test public void testParse_invalidPolygon() throws IOException { /** @@ -225,6 +277,15 @@ public class GeoJSONShapeParserTests extends ElasticsearchTestCase { parser = JsonXContent.jsonXContent.createParser(invalidPoly5); parser.nextToken(); ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchIllegalArgumentException.class); + + // test case 6: create an invalid polygon with 0 LinearRings + String invalidPoly6 = XContentFactory.jsonBuilder().startObject().field("type", "polygon") + .startArray("coordinates").endArray() + .endObject().string(); + + parser = JsonXContent.jsonXContent.createParser(invalidPoly6); + parser.nextToken(); + ElasticsearchGeoAssertions.assertValidException(parser, ElasticsearchParseException.class); } @Test