2828import com .vividsolutions .jts .geom .GeometryFactory ;
2929import org .apache .commons .lang3 .tuple .Pair ;
3030import org .elasticsearch .ElasticsearchParseException ;
31+ import org .elasticsearch .common .Explicit ;
3132import org .elasticsearch .common .logging .ESLogger ;
3233import org .elasticsearch .common .logging .ESLoggerFactory ;
3334import org .elasticsearch .common .unit .DistanceUnit .Distance ;
@@ -728,7 +729,9 @@ public static ShapeBuilder parse(XContentParser parser, GeoShapeFieldMapper shap
728729 Distance radius = null ;
729730 CoordinateNode node = null ;
730731 GeometryCollectionBuilder geometryCollections = null ;
732+
731733 Orientation requestedOrientation = (shapeMapper == null ) ? Orientation .RIGHT : shapeMapper .fieldType ().orientation ();
734+ boolean coerce = (shapeMapper == null ) ? GeoShapeFieldMapper .Defaults .COERCE .value () : shapeMapper .coerce ().value ();
732735
733736 XContentParser .Token token ;
734737 while ((token = parser .nextToken ()) != XContentParser .Token .END_OBJECT ) {
@@ -743,7 +746,7 @@ public static ShapeBuilder parse(XContentParser parser, GeoShapeFieldMapper shap
743746 node = parseCoordinates (parser );
744747 } else if (FIELD_GEOMETRIES .equals (fieldName )) {
745748 parser .nextToken ();
746- geometryCollections = parseGeometries (parser , requestedOrientation );
749+ geometryCollections = parseGeometries (parser , shapeMapper );
747750 } else if (CircleBuilder .FIELD_RADIUS .equals (fieldName )) {
748751 parser .nextToken ();
749752 radius = Distance .parseDistance (parser .text ());
@@ -772,8 +775,8 @@ public static ShapeBuilder parse(XContentParser parser, GeoShapeFieldMapper shap
772775 case MULTIPOINT : return parseMultiPoint (node );
773776 case LINESTRING : return parseLineString (node );
774777 case MULTILINESTRING : return parseMultiLine (node );
775- case POLYGON : return parsePolygon (node , requestedOrientation );
776- case MULTIPOLYGON : return parseMultiPolygon (node , requestedOrientation );
778+ case POLYGON : return parsePolygon (node , requestedOrientation , coerce );
779+ case MULTIPOLYGON : return parseMultiPolygon (node , requestedOrientation , coerce );
777780 case CIRCLE : return parseCircle (node , radius );
778781 case ENVELOPE : return parseEnvelope (node , requestedOrientation );
779782 case GEOMETRYCOLLECTION : return geometryCollections ;
@@ -801,7 +804,7 @@ protected static CircleBuilder parseCircle(CoordinateNode coordinates, Distance
801804 return newCircleBuilder ().center (coordinates .coordinate ).radius (radius );
802805 }
803806
804- protected static EnvelopeBuilder parseEnvelope (CoordinateNode coordinates , Orientation orientation ) {
807+ protected static EnvelopeBuilder parseEnvelope (CoordinateNode coordinates , final Orientation orientation ) {
805808 // validate the coordinate array for envelope type
806809 if (coordinates .children .size () != 2 ) {
807810 throw new ElasticsearchParseException ("invalid number of points [{}] provided for " +
@@ -868,7 +871,7 @@ protected static MultiLineStringBuilder parseMultiLine(CoordinateNode coordinate
868871 return multiline ;
869872 }
870873
871- protected static LineStringBuilder parseLinearRing (CoordinateNode coordinates ) {
874+ protected static LineStringBuilder parseLinearRing (CoordinateNode coordinates , boolean coerce ) {
872875 /**
873876 * Per GeoJSON spec (http://geojson.org/geojson-spec.html#linestring)
874877 * A LinearRing is closed LineString with 4 or more positions. The first and last positions
@@ -880,32 +883,43 @@ protected static LineStringBuilder parseLinearRing(CoordinateNode coordinates) {
880883 error += (coordinates .coordinate == null ) ?
881884 " No coordinate array provided" : " Found a single coordinate when expecting a coordinate array" ;
882885 throw new ElasticsearchParseException (error );
883- } else if (coordinates .children .size () < 4 ) {
884- throw new ElasticsearchParseException ("invalid number of points in LinearRing (found [{}] - must be >= 4)" , coordinates .children .size ());
885- } else if (!coordinates .children .get (0 ).coordinate .equals (
886- coordinates .children .get (coordinates .children .size () - 1 ).coordinate )) {
887- throw new ElasticsearchParseException ("invalid LinearRing found (coordinates are not closed)" );
886+ }
887+
888+ int numValidPts ;
889+ if (coordinates .children .size () < (numValidPts = (coerce ) ? 3 : 4 )) {
890+ throw new ElasticsearchParseException ("invalid number of points in LinearRing (found [{}] - must be >= " + numValidPts + ")(" ,
891+ coordinates .children .size ());
892+ }
893+
894+ if (!coordinates .children .get (0 ).coordinate .equals (
895+ coordinates .children .get (coordinates .children .size () - 1 ).coordinate )) {
896+ if (coerce ) {
897+ coordinates .children .add (coordinates .children .get (0 ));
898+ } else {
899+ throw new ElasticsearchParseException ("invalid LinearRing found (coordinates are not closed)" );
900+ }
888901 }
889902 return parseLineString (coordinates );
890903 }
891904
892- protected static PolygonBuilder parsePolygon (CoordinateNode coordinates , Orientation orientation ) {
905+ protected static PolygonBuilder parsePolygon (CoordinateNode coordinates , final Orientation orientation , final boolean coerce ) {
893906 if (coordinates .children == null || coordinates .children .isEmpty ()) {
894907 throw new ElasticsearchParseException ("invalid LinearRing provided for type polygon. Linear ring must be an array of coordinates" );
895908 }
896909
897- LineStringBuilder shell = parseLinearRing (coordinates .children .get (0 ));
910+ LineStringBuilder shell = parseLinearRing (coordinates .children .get (0 ), coerce );
898911 PolygonBuilder polygon = new PolygonBuilder (shell .points , orientation );
899912 for (int i = 1 ; i < coordinates .children .size (); i ++) {
900- polygon .hole (parseLinearRing (coordinates .children .get (i )));
913+ polygon .hole (parseLinearRing (coordinates .children .get (i ), coerce ));
901914 }
902915 return polygon ;
903916 }
904917
905- protected static MultiPolygonBuilder parseMultiPolygon (CoordinateNode coordinates , Orientation orientation ) {
918+ protected static MultiPolygonBuilder parseMultiPolygon (CoordinateNode coordinates , final Orientation orientation ,
919+ final boolean coerce ) {
906920 MultiPolygonBuilder polygons = newMultiPolygon (orientation );
907921 for (CoordinateNode node : coordinates .children ) {
908- polygons .polygon (parsePolygon (node , orientation ));
922+ polygons .polygon (parsePolygon (node , orientation , coerce ));
909923 }
910924 return polygons ;
911925 }
@@ -917,13 +931,15 @@ protected static MultiPolygonBuilder parseMultiPolygon(CoordinateNode coordinate
917931 * @return Geometry[] geometries of the GeometryCollection
918932 * @throws IOException Thrown if an error occurs while reading from the XContentParser
919933 */
920- protected static GeometryCollectionBuilder parseGeometries (XContentParser parser , Orientation orientation ) throws IOException {
934+ protected static GeometryCollectionBuilder parseGeometries (XContentParser parser , GeoShapeFieldMapper mapper ) throws
935+ IOException {
921936 if (parser .currentToken () != XContentParser .Token .START_ARRAY ) {
922937 throw new ElasticsearchParseException ("geometries must be an array of geojson objects" );
923938 }
924939
925940 XContentParser .Token token = parser .nextToken ();
926- GeometryCollectionBuilder geometryCollection = newGeometryCollection (orientation );
941+ GeometryCollectionBuilder geometryCollection = newGeometryCollection ( (mapper == null ) ? Orientation .RIGHT : mapper
942+ .fieldType ().orientation ());
927943 while (token != XContentParser .Token .END_ARRAY ) {
928944 ShapeBuilder shapeBuilder = GeoShapeType .parse (parser );
929945 geometryCollection .shape (shapeBuilder );
0 commit comments