Skip to content

Commit 54e1d24

Browse files
authored
[7.15] Remove InvalidShapeException from GeoPolygonDecomposer (#77613) (#77740)
fixes a bug where InvalidShapeException are not properly handle so even if the mappings defined with ignore_malformed set to true, the exception leaks and the setting is ignored
1 parent 7c17e3f commit 54e1d24

File tree

4 files changed

+49
-14
lines changed

4 files changed

+49
-14
lines changed

server/src/main/java/org/elasticsearch/common/geo/GeoPolygonDecomposer.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import org.elasticsearch.geometry.MultiPolygon;
1414
import org.elasticsearch.geometry.Point;
1515
import org.elasticsearch.geometry.Polygon;
16-
import org.locationtech.spatial4j.exception.InvalidShapeException;
1716

1817
import java.util.ArrayList;
1918
import java.util.Arrays;
@@ -192,7 +191,7 @@ private static Edge[] ring(int component, boolean direction, boolean handedness,
192191
}
193192
if (signedArea == 0) {
194193
// Points are collinear or self-intersection
195-
throw new InvalidShapeException("Cannot determine orientation: signed area equal to 0." +
194+
throw new IllegalArgumentException("Cannot determine orientation: signed area equal to 0." +
196195
" Points are collinear or polygon self-intersects.");
197196
}
198197
boolean orientation = signedArea < 0;
@@ -339,7 +338,7 @@ private static Edge[] concat(int component, boolean direction, Point[] points, f
339338
edges[edgeOffset + i - 1].next = edges[edgeOffset + i] = new Edge(nextPoint, null);
340339
edges[edgeOffset + i - 1].component = component;
341340
} else {
342-
throw new InvalidShapeException("Provided shape has duplicate consecutive coordinates at: (" + nextPoint + ")");
341+
throw new IllegalArgumentException("Provided shape has duplicate consecutive coordinates at: (" + nextPoint + ")");
343342
}
344343
}
345344

@@ -464,7 +463,7 @@ private static void assign(Edge[] holes, Point[][] points, int numHoles, Edge[]
464463
if (intersections == 0) {
465464
// There were no edges that intersect the line of longitude through
466465
// holes[i].coordinate, so there's no way this hole is within the polygon.
467-
throw new InvalidShapeException("Invalid shape: Hole is not within polygon");
466+
throw new IllegalArgumentException("Invalid shape: Hole is not within polygon");
468467
}
469468

470469
// Next we do a binary search to find the position of holes[i].coordinate in the array.
@@ -480,7 +479,7 @@ private static void assign(Edge[] holes, Point[][] points, int numHoles, Edge[]
480479
// and it didn't match after all.
481480

482481
// TODO Can this actually happen? Needs a test to exercise it, or else needs to be removed.
483-
throw new InvalidShapeException("Invalid shape: Hole is not within polygon");
482+
throw new IllegalArgumentException("Invalid shape: Hole is not within polygon");
484483
}
485484

486485
final int index;
@@ -546,7 +545,7 @@ private static int component(final Edge edge, final int id, final ArrayList<Edge
546545
partitionPoint[1] = current.coordinate.getY();
547546
partitionPoint[2] = current.coordinate.getZ();
548547
if (connectedComponents > 0 && current.next != edge) {
549-
throw new InvalidShapeException("Shape contains more than one shared point");
548+
throw new IllegalArgumentException("Shape contains more than one shared point");
550549
}
551550

552551
// a negative id flags the edge as visited for the edges(...) method.
@@ -594,10 +593,10 @@ private static Point[] coordinates(Edge component, Point[] coordinates, double[]
594593
// First and last coordinates must be equal
595594
if (coordinates[0].equals(coordinates[coordinates.length - 1]) == false) {
596595
if (Double.isNaN(partitionPoint[2])) {
597-
throw new InvalidShapeException("Self-intersection at or near point ["
596+
throw new IllegalArgumentException("Self-intersection at or near point ["
598597
+ partitionPoint[0] + "," + partitionPoint[1] + "]");
599598
} else {
600-
throw new InvalidShapeException("Self-intersection at or near point ["
599+
throw new IllegalArgumentException("Self-intersection at or near point ["
601600
+ partitionPoint[0] + "," + partitionPoint[1] + "," + partitionPoint[2] + "]");
602601
}
603602
}
@@ -728,7 +727,7 @@ void setNext(Edge next) {
728727
if (next != null) {
729728
// self-loop throws an invalid shape
730729
if (this.coordinate.equals(next.coordinate)) {
731-
throw new InvalidShapeException("Provided shape has duplicate consecutive coordinates at: " + this.coordinate);
730+
throw new IllegalArgumentException("Provided shape has duplicate consecutive coordinates at: " + this.coordinate);
732731
}
733732
this.next = next;
734733
}

server/src/test/java/org/elasticsearch/common/geo/GeometryIndexerTests.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import org.elasticsearch.geometry.ShapeType;
2828
import org.elasticsearch.index.mapper.GeoShapeIndexer;
2929
import org.elasticsearch.test.ESTestCase;
30-
import org.locationtech.spatial4j.exception.InvalidShapeException;
3130

3231
import java.io.IOException;
3332
import java.text.ParseException;
@@ -431,7 +430,7 @@ public void testInvalidSelfCrossingPolygon() {
431430
Polygon polygon = new Polygon(new LinearRing(
432431
new double[]{0, 0, 1, 0.5, 1.5, 1, 2, 2, 0}, new double[]{0, 2, 1.9, 1.8, 1.8, 1.9, 2, 0, 0}
433432
));
434-
Exception e = expectThrows(InvalidShapeException.class, () -> indexer.prepareForIndexing(polygon));
433+
Exception e = expectThrows(IllegalArgumentException.class, () -> indexer.prepareForIndexing(polygon));
435434
assertThat(e.getMessage(), containsString("Self-intersection at or near point ["));
436435
assertThat(e.getMessage(), not(containsString("NaN")));
437436
}

server/src/test/java/org/elasticsearch/common/geo/ShapeBuilderTests.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -834,9 +834,6 @@ public void testInvalidSelfCrossingPolygon() {
834834
Exception e = expectThrows(InvalidShapeException.class, () -> builder.close().buildS4J());
835835
assertThat(e.getMessage(), containsString("Self-intersection at or near point ["));
836836
assertThat(e.getMessage(), not(containsString("NaN")));
837-
e = expectThrows(InvalidShapeException.class, () -> buildGeometry(builder.close()));
838-
assertThat(e.getMessage(), containsString("Self-intersection at or near point ["));
839-
assertThat(e.getMessage(), not(containsString("NaN")));
840837
}
841838

842839
public Object buildGeometry(ShapeBuilder<?, ?, ?> builder) {

x-pack/plugin/spatial/src/test/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapperTests.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.elasticsearch.index.mapper.DocumentMapper;
2727
import org.elasticsearch.index.mapper.MappedFieldType;
2828
import org.elasticsearch.index.mapper.Mapper;
29+
import org.elasticsearch.index.mapper.MapperParsingException;
2930
import org.elasticsearch.index.mapper.MapperService;
3031
import org.elasticsearch.index.mapper.MapperTestCase;
3132
import org.elasticsearch.index.mapper.ParsedDocument;
@@ -38,6 +39,7 @@
3839
import java.util.Collection;
3940
import java.util.Collections;
4041

42+
import static org.hamcrest.Matchers.containsString;
4143
import static org.hamcrest.Matchers.equalTo;
4244
import static org.hamcrest.Matchers.hasSize;
4345
import static org.hamcrest.Matchers.instanceOf;
@@ -225,6 +227,44 @@ public void testIgnoreMalformedParsing() throws IOException {
225227
assertThat(ignoreMalformed, equalTo(false));
226228
}
227229

230+
public void testIgnoreMalformedValues() throws IOException {
231+
232+
DocumentMapper ignoreMapper = createDocumentMapper(fieldMapping(b -> {
233+
b.field("type", "geo_shape");
234+
b.field("ignore_malformed", true);
235+
}));
236+
DocumentMapper failMapper = createDocumentMapper(fieldMapping(b -> {
237+
b.field("type", "geo_shape");
238+
b.field("ignore_malformed", false);
239+
}));
240+
241+
{
242+
BytesReference arrayedDoc = BytesReference.bytes(XContentFactory.jsonBuilder()
243+
.startObject()
244+
.field("field", "Bad shape")
245+
.endObject()
246+
);
247+
SourceToParse sourceToParse = new SourceToParse("test", "_doc", "1", arrayedDoc, XContentType.JSON);
248+
ParsedDocument document = ignoreMapper.parse(sourceToParse);
249+
assertThat(document.docs().get(0).getFields("field").length, equalTo(0));
250+
MapperParsingException exception = expectThrows(MapperParsingException.class, () -> failMapper.parse(sourceToParse));
251+
assertThat(exception.getCause().getMessage(), containsString("Unknown geometry type: bad"));
252+
}
253+
{
254+
BytesReference arrayedDoc = BytesReference.bytes(XContentFactory.jsonBuilder()
255+
.startObject()
256+
.field("field", "POLYGON ((18.9401790919516 -33.9681188869036, 18.9401790919516 -33.9681188869037, 18.9401790919517 " +
257+
"-33.9681188869037, 18.9401790919517 -33.9681188869036, 18.9401790919516 -33.9681188869036))")
258+
.endObject()
259+
);
260+
SourceToParse sourceToParse = new SourceToParse("test", "_doc", "1", arrayedDoc, XContentType.JSON);
261+
ParsedDocument document = ignoreMapper.parse(sourceToParse);
262+
assertThat(document.docs().get(0).getFields("field").length, equalTo(0));
263+
MapperParsingException exception = expectThrows(MapperParsingException.class, () -> failMapper.parse(sourceToParse));
264+
assertThat(exception.getCause().getMessage(), containsString("Cannot determine orientation"));
265+
}
266+
}
267+
228268
/**
229269
* Test that doc_values parameter correctly parses
230270
*/

0 commit comments

Comments
 (0)