Geo: Add coerce support to libs/geo WKT parser (#43273)

Adds support for coercing not closed polygons and ignoring Z value
to libs/geo WKT parser.

Closes #43173
This commit is contained in:
Igor Motov 2019-06-18 07:03:45 -07:00
parent de1a685cce
commit 9f7d1ff2de
19 changed files with 126 additions and 47 deletions

View File

@ -22,7 +22,7 @@ package org.elasticsearch.geo.geometry;
/**
* Geometry-related utility methods
*/
final class GeometryUtils {
public final class GeometryUtils {
/**
* Minimum longitude value.
*/
@ -67,4 +67,12 @@ final class GeometryUtils {
}
}
public static double checkAltitude(final boolean ignoreZValue, double zValue) {
if (ignoreZValue == false) {
throw new IllegalArgumentException("found Z value [" + zValue + "] but [ignore_z_value] "
+ "parameter is [" + ignoreZValue + "]");
}
return zValue;
}
}

View File

@ -22,6 +22,7 @@ package org.elasticsearch.geo.utils;
import org.elasticsearch.geo.geometry.Circle;
import org.elasticsearch.geo.geometry.Geometry;
import org.elasticsearch.geo.geometry.GeometryCollection;
import org.elasticsearch.geo.geometry.GeometryUtils;
import org.elasticsearch.geo.geometry.GeometryVisitor;
import org.elasticsearch.geo.geometry.Line;
import org.elasticsearch.geo.geometry.LinearRing;
@ -52,12 +53,16 @@ public class WellKnownText {
public static final String COMMA = ",";
public static final String NAN = "NaN";
private static final String NUMBER = "<NUMBER>";
private static final String EOF = "END-OF-STREAM";
private static final String EOL = "END-OF-LINE";
private final String NUMBER = "<NUMBER>";
private final String EOF = "END-OF-STREAM";
private final String EOL = "END-OF-LINE";
public WellKnownText() {
private final boolean coerce;
private final boolean ignoreZValue;
public WellKnownText(boolean coerce, boolean ignoreZValue) {
this.coerce = coerce;
this.ignoreZValue = ignoreZValue;
}
public String toWKT(Geometry geometry) {
@ -247,7 +252,7 @@ public class WellKnownText {
/**
* parse geometry from the stream tokenizer
*/
private static Geometry parseGeometry(StreamTokenizer stream) throws IOException, ParseException {
private Geometry parseGeometry(StreamTokenizer stream) throws IOException, ParseException {
final String type = nextWord(stream).toLowerCase(Locale.ROOT);
switch (type) {
case "point":
@ -272,7 +277,7 @@ public class WellKnownText {
throw new IllegalArgumentException("Unknown geometry type: " + type);
}
private static GeometryCollection<Geometry> parseGeometryCollection(StreamTokenizer stream) throws IOException, ParseException {
private GeometryCollection<Geometry> parseGeometryCollection(StreamTokenizer stream) throws IOException, ParseException {
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
return GeometryCollection.EMPTY;
}
@ -284,7 +289,7 @@ public class WellKnownText {
return new GeometryCollection<>(shapes);
}
private static Point parsePoint(StreamTokenizer stream) throws IOException, ParseException {
private Point parsePoint(StreamTokenizer stream) throws IOException, ParseException {
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
return Point.EMPTY;
}
@ -292,7 +297,7 @@ public class WellKnownText {
double lat = nextNumber(stream);
Point pt;
if (isNumberNext(stream)) {
pt = new Point(lat, lon, nextNumber(stream));
pt = new Point(lat, lon, GeometryUtils.checkAltitude(ignoreZValue, nextNumber(stream)));
} else {
pt = new Point(lat, lon);
}
@ -300,7 +305,7 @@ public class WellKnownText {
return pt;
}
private static void parseCoordinates(StreamTokenizer stream, ArrayList<Double> lats, ArrayList<Double> lons, ArrayList<Double> alts)
private void parseCoordinates(StreamTokenizer stream, ArrayList<Double> lats, ArrayList<Double> lons, ArrayList<Double> alts)
throws IOException, ParseException {
parseCoordinate(stream, lats, lons, alts);
while (nextCloserOrComma(stream).equals(COMMA)) {
@ -308,19 +313,19 @@ public class WellKnownText {
}
}
private static void parseCoordinate(StreamTokenizer stream, ArrayList<Double> lats, ArrayList<Double> lons, ArrayList<Double> alts)
private void parseCoordinate(StreamTokenizer stream, ArrayList<Double> lats, ArrayList<Double> lons, ArrayList<Double> alts)
throws IOException, ParseException {
lons.add(nextNumber(stream));
lats.add(nextNumber(stream));
if (isNumberNext(stream)) {
alts.add(nextNumber(stream));
alts.add(GeometryUtils.checkAltitude(ignoreZValue, nextNumber(stream)));
}
if (alts.isEmpty() == false && alts.size() != lons.size()) {
throw new ParseException("coordinate dimensions do not match: " + tokenString(stream), stream.lineno());
}
}
private static MultiPoint parseMultiPoint(StreamTokenizer stream) throws IOException, ParseException {
private MultiPoint parseMultiPoint(StreamTokenizer stream) throws IOException, ParseException {
String token = nextEmptyOrOpen(stream);
if (token.equals(EMPTY)) {
return MultiPoint.EMPTY;
@ -340,7 +345,7 @@ public class WellKnownText {
return new MultiPoint(Collections.unmodifiableList(points));
}
private static Line parseLine(StreamTokenizer stream) throws IOException, ParseException {
private Line parseLine(StreamTokenizer stream) throws IOException, ParseException {
String token = nextEmptyOrOpen(stream);
if (token.equals(EMPTY)) {
return Line.EMPTY;
@ -356,7 +361,7 @@ public class WellKnownText {
}
}
private static MultiLine parseMultiLine(StreamTokenizer stream) throws IOException, ParseException {
private MultiLine parseMultiLine(StreamTokenizer stream) throws IOException, ParseException {
String token = nextEmptyOrOpen(stream);
if (token.equals(EMPTY)) {
return MultiLine.EMPTY;
@ -369,12 +374,13 @@ public class WellKnownText {
return new MultiLine(Collections.unmodifiableList(lines));
}
private static LinearRing parsePolygonHole(StreamTokenizer stream) throws IOException, ParseException {
private LinearRing parsePolygonHole(StreamTokenizer stream) throws IOException, ParseException {
nextOpener(stream);
ArrayList<Double> lats = new ArrayList<>();
ArrayList<Double> lons = new ArrayList<>();
ArrayList<Double> alts = new ArrayList<>();
parseCoordinates(stream, lats, lons, alts);
closeLinearRingIfCoerced(lats, lons, alts);
if (alts.isEmpty()) {
return new LinearRing(toArray(lats), toArray(lons));
} else {
@ -382,7 +388,7 @@ public class WellKnownText {
}
}
private static Polygon parsePolygon(StreamTokenizer stream) throws IOException, ParseException {
private Polygon parsePolygon(StreamTokenizer stream) throws IOException, ParseException {
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
return Polygon.EMPTY;
}
@ -395,6 +401,7 @@ public class WellKnownText {
while (nextCloserOrComma(stream).equals(COMMA)) {
holes.add(parsePolygonHole(stream));
}
closeLinearRingIfCoerced(lats, lons, alts);
LinearRing shell;
if (alts.isEmpty()) {
shell = new LinearRing(toArray(lats), toArray(lons));
@ -408,7 +415,25 @@ public class WellKnownText {
}
}
private static MultiPolygon parseMultiPolygon(StreamTokenizer stream) throws IOException, ParseException {
/**
* Treats supplied arrays as coordinates of a linear ring. If the ring is not closed and coerce is set to true,
* the first set of coordinates (lat, lon and alt if available) are added to the end of the arrays.
*/
private void closeLinearRingIfCoerced(ArrayList<Double> lats, ArrayList<Double> lons, ArrayList<Double> alts) {
if (coerce && lats.isEmpty() == false && lons.isEmpty() == false) {
int last = lats.size() - 1;
if (!lats.get(0).equals(lats.get(last)) || !lons.get(0).equals(lons.get(last)) ||
(alts.isEmpty() == false && !alts.get(0).equals(alts.get(last)))) {
lons.add(lons.get(0));
lats.add(lats.get(0));
if (alts.isEmpty() == false) {
alts.add(alts.get(0));
}
}
}
}
private MultiPolygon parseMultiPolygon(StreamTokenizer stream) throws IOException, ParseException {
String token = nextEmptyOrOpen(stream);
if (token.equals(EMPTY)) {
return MultiPolygon.EMPTY;
@ -421,7 +446,7 @@ public class WellKnownText {
return new MultiPolygon(Collections.unmodifiableList(polygons));
}
private static Rectangle parseBBox(StreamTokenizer stream) throws IOException, ParseException {
private Rectangle parseBBox(StreamTokenizer stream) throws IOException, ParseException {
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
return Rectangle.EMPTY;
}
@ -438,7 +463,7 @@ public class WellKnownText {
}
private static Circle parseCircle(StreamTokenizer stream) throws IOException, ParseException {
private Circle parseCircle(StreamTokenizer stream) throws IOException, ParseException {
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
return Circle.EMPTY;
}
@ -457,7 +482,7 @@ public class WellKnownText {
/**
* next word in the stream
*/
private static String nextWord(StreamTokenizer stream) throws ParseException, IOException {
private String nextWord(StreamTokenizer stream) throws ParseException, IOException {
switch (stream.nextToken()) {
case StreamTokenizer.TT_WORD:
final String word = stream.sval;
@ -472,7 +497,7 @@ public class WellKnownText {
throw new ParseException("expected word but found: " + tokenString(stream), stream.lineno());
}
private static double nextNumber(StreamTokenizer stream) throws IOException, ParseException {
private double nextNumber(StreamTokenizer stream) throws IOException, ParseException {
if (stream.nextToken() == StreamTokenizer.TT_WORD) {
if (stream.sval.equalsIgnoreCase(NAN)) {
return Double.NaN;
@ -487,7 +512,7 @@ public class WellKnownText {
throw new ParseException("expected number but found: " + tokenString(stream), stream.lineno());
}
private static String tokenString(StreamTokenizer stream) {
private String tokenString(StreamTokenizer stream) {
switch (stream.ttype) {
case StreamTokenizer.TT_WORD:
return stream.sval;
@ -501,13 +526,13 @@ public class WellKnownText {
return "'" + (char) stream.ttype + "'";
}
private static boolean isNumberNext(StreamTokenizer stream) throws IOException {
private boolean isNumberNext(StreamTokenizer stream) throws IOException {
final int type = stream.nextToken();
stream.pushBack();
return type == StreamTokenizer.TT_WORD;
}
private static String nextEmptyOrOpen(StreamTokenizer stream) throws IOException, ParseException {
private String nextEmptyOrOpen(StreamTokenizer stream) throws IOException, ParseException {
final String next = nextWord(stream);
if (next.equals(EMPTY) || next.equals(LPAREN)) {
return next;
@ -516,28 +541,28 @@ public class WellKnownText {
+ " but found: " + tokenString(stream), stream.lineno());
}
private static String nextCloser(StreamTokenizer stream) throws IOException, ParseException {
private String nextCloser(StreamTokenizer stream) throws IOException, ParseException {
if (nextWord(stream).equals(RPAREN)) {
return RPAREN;
}
throw new ParseException("expected " + RPAREN + " but found: " + tokenString(stream), stream.lineno());
}
private static String nextComma(StreamTokenizer stream) throws IOException, ParseException {
private String nextComma(StreamTokenizer stream) throws IOException, ParseException {
if (nextWord(stream).equals(COMMA) == true) {
return COMMA;
}
throw new ParseException("expected " + COMMA + " but found: " + tokenString(stream), stream.lineno());
}
private static String nextOpener(StreamTokenizer stream) throws IOException, ParseException {
private String nextOpener(StreamTokenizer stream) throws IOException, ParseException {
if (nextWord(stream).equals(LPAREN)) {
return LPAREN;
}
throw new ParseException("expected " + LPAREN + " but found: " + tokenString(stream), stream.lineno());
}
private static String nextCloserOrComma(StreamTokenizer stream) throws IOException, ParseException {
private String nextCloserOrComma(StreamTokenizer stream) throws IOException, ParseException {
String token = nextWord(stream);
if (token.equals(COMMA) || token.equals(RPAREN)) {
return token;
@ -546,7 +571,7 @@ public class WellKnownText {
+ " but found: " + tokenString(stream), stream.lineno());
}
public static String getWKTName(Geometry geometry) {
private static String getWKTName(Geometry geometry) {
return geometry.visit(new GeometryVisitor<String, RuntimeException>() {
@Override
public String visit(Circle circle) {
@ -600,7 +625,7 @@ public class WellKnownText {
});
}
private static double[] toArray(ArrayList<Double> doubles) {
private double[] toArray(ArrayList<Double> doubles) {
return doubles.stream().mapToDouble(i -> i).toArray();
}

View File

@ -53,7 +53,7 @@ abstract class BaseGeometryTestCase<T extends Geometry> extends AbstractWireTest
@SuppressWarnings("unchecked")
@Override
protected T copyInstance(T instance, Version version) throws IOException {
WellKnownText wkt = new WellKnownText();
WellKnownText wkt = new WellKnownText(true, true);
String text = wkt.toWKT(instance);
try {
return (T) wkt.fromWKT(text);

View File

@ -36,7 +36,7 @@ public class CircleTests extends BaseGeometryTestCase<Circle> {
}
public void testBasicSerialization() throws IOException, ParseException {
WellKnownText wkt = new WellKnownText();
WellKnownText wkt = new WellKnownText(true, true);
assertEquals("circle (20.0 10.0 15.0)", wkt.toWKT(new Circle(10, 20, 15)));
assertEquals(new Circle(10, 20, 15), wkt.fromWKT("circle (20.0 10.0 15.0)"));

View File

@ -35,7 +35,7 @@ public class GeometryCollectionTests extends BaseGeometryTestCase<GeometryCollec
public void testBasicSerialization() throws IOException, ParseException {
WellKnownText wkt = new WellKnownText();
WellKnownText wkt = new WellKnownText(true, true);
assertEquals("geometrycollection (point (20.0 10.0),point EMPTY)",
wkt.toWKT(new GeometryCollection<Geometry>(Arrays.asList(new Point(10, 20), Point.EMPTY))));

View File

@ -31,7 +31,7 @@ public class LineTests extends BaseGeometryTestCase<Line> {
}
public void testBasicSerialization() throws IOException, ParseException {
WellKnownText wkt = new WellKnownText();
WellKnownText wkt = new WellKnownText(true, true);
assertEquals("linestring (3.0 1.0, 4.0 2.0)", wkt.toWKT(new Line(new double[]{1, 2}, new double[]{3, 4})));
assertEquals(new Line(new double[]{1, 2}, new double[]{3, 4}), wkt.fromWKT("linestring (3 1, 4 2)"));
@ -54,4 +54,10 @@ public class LineTests extends BaseGeometryTestCase<Line> {
ex = expectThrows(IllegalArgumentException.class, () -> new Line(new double[]{1, 100, 3, 1}, new double[]{3, 4, 5, 3}));
assertEquals("invalid latitude 100.0; must be between -90.0 and 90.0", ex.getMessage());
}
public void testWKTValidation() {
IllegalArgumentException ex = expectThrows(IllegalArgumentException.class,
() -> new WellKnownText(randomBoolean(), false).fromWKT("linestring (3 1 6, 4 2 5)"));
assertEquals("found Z value [6.0] but [ignore_z_value] parameter is [false]", ex.getMessage());
}
}

View File

@ -26,7 +26,7 @@ public class LinearRingTests extends ESTestCase {
public void testBasicSerialization() {
UnsupportedOperationException ex = expectThrows(UnsupportedOperationException.class,
() -> new WellKnownText().toWKT(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3})));
() -> new WellKnownText(true, true).toWKT(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3})));
assertEquals("line ring cannot be serialized using WKT", ex.getMessage());
}

View File

@ -40,7 +40,7 @@ public class MultiLineTests extends BaseGeometryTestCase<MultiLine> {
}
public void testBasicSerialization() throws IOException, ParseException {
WellKnownText wkt = new WellKnownText();
WellKnownText wkt = new WellKnownText(true, true);
assertEquals("multilinestring ((3.0 1.0, 4.0 2.0))", wkt.toWKT(
new MultiLine(Collections.singletonList(new Line(new double[]{1, 2}, new double[]{3, 4})))));
assertEquals(new MultiLine(Collections.singletonList(new Line(new double[]{1, 2}, new double[]{3, 4}))),

View File

@ -41,7 +41,7 @@ public class MultiPointTests extends BaseGeometryTestCase<MultiPoint> {
}
public void testBasicSerialization() throws IOException, ParseException {
WellKnownText wkt = new WellKnownText();
WellKnownText wkt = new WellKnownText(true, true);
assertEquals("multipoint (2.0 1.0)", wkt.toWKT(
new MultiPoint(Collections.singletonList(new Point(1, 2)))));
assertEquals(new MultiPoint(Collections.singletonList(new Point(1 ,2))),

View File

@ -40,7 +40,7 @@ public class MultiPolygonTests extends BaseGeometryTestCase<MultiPolygon> {
}
public void testBasicSerialization() throws IOException, ParseException {
WellKnownText wkt = new WellKnownText();
WellKnownText wkt = new WellKnownText(true, true);
assertEquals("multipolygon (((3.0 1.0, 4.0 2.0, 5.0 3.0, 3.0 1.0)))",
wkt.toWKT(new MultiPolygon(Collections.singletonList(
new Polygon(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3}))))));

View File

@ -31,7 +31,7 @@ public class PointTests extends BaseGeometryTestCase<Point> {
}
public void testBasicSerialization() throws IOException, ParseException {
WellKnownText wkt = new WellKnownText();
WellKnownText wkt = new WellKnownText(true, true);
assertEquals("point (20.0 10.0)", wkt.toWKT(new Point(10, 20)));
assertEquals(new Point(10, 20), wkt.fromWKT("point (20.0 10.0)"));
@ -49,4 +49,10 @@ public class PointTests extends BaseGeometryTestCase<Point> {
ex = expectThrows(IllegalArgumentException.class, () -> new Point(10, 500));
assertEquals("invalid longitude 500.0; must be between -180.0 and 180.0", ex.getMessage());
}
public void testWKTValidation() {
IllegalArgumentException ex = expectThrows(IllegalArgumentException.class,
() -> new WellKnownText(randomBoolean(), false).fromWKT("point (20.0 10.0 100.0)"));
assertEquals("found Z value [100.0] but [ignore_z_value] parameter is [false]", ex.getMessage());
}
}

View File

@ -32,7 +32,7 @@ public class PolygonTests extends BaseGeometryTestCase<Polygon> {
}
public void testBasicSerialization() throws IOException, ParseException {
WellKnownText wkt = new WellKnownText();
WellKnownText wkt = new WellKnownText(true, true);
assertEquals("polygon ((3.0 1.0, 4.0 2.0, 5.0 3.0, 3.0 1.0))",
wkt.toWKT(new Polygon(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3}))));
assertEquals(new Polygon(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3})),
@ -43,6 +43,15 @@ public class PolygonTests extends BaseGeometryTestCase<Polygon> {
assertEquals(new Polygon(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3}, new double[]{5, 4, 3, 5})),
wkt.fromWKT("polygon ((3 1 5, 4 2 4, 5 3 3, 3 1 5))"));
// Auto closing in coerce mode
assertEquals(new Polygon(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3})),
wkt.fromWKT("polygon ((3 1, 4 2, 5 3))"));
assertEquals(new Polygon(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3}, new double[]{5, 4, 3, 5})),
wkt.fromWKT("polygon ((3 1 5, 4 2 4, 5 3 3))"));
assertEquals(new Polygon(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3}),
Collections.singletonList(new LinearRing(new double[]{1.5, 1.5, 1.0, 1.5}, new double[]{0.5, 2.5, 2.0, 0.5}))),
wkt.fromWKT("polygon ((3 1, 4 2, 5 3, 3 1), (0.5 1.5, 2.5 1.5, 2.0 1.0))"));
assertEquals("polygon EMPTY", wkt.toWKT(Polygon.EMPTY));
assertEquals(Polygon.EMPTY, wkt.fromWKT("polygon EMPTY)"));
}
@ -61,4 +70,20 @@ public class PolygonTests extends BaseGeometryTestCase<Polygon> {
Collections.singletonList(new LinearRing(new double[]{1, 2, 3, 1}, new double[]{3, 4, 5, 3}))));
assertEquals("holes must have the same number of dimensions as the polygon", ex.getMessage());
}
public void testWKTValidation() {
IllegalArgumentException ex = expectThrows(IllegalArgumentException.class,
() -> new WellKnownText(false, true).fromWKT("polygon ((3 1 5, 4 2 4, 5 3 3))"));
assertEquals("first and last points of the linear ring must be the same (it must close itself): " +
"lats[0]=1.0 lats[2]=3.0 lons[0]=3.0 lons[2]=5.0 alts[0]=5.0 alts[2]=3.0", ex.getMessage());
ex = expectThrows(IllegalArgumentException.class,
() -> new WellKnownText(randomBoolean(), false).fromWKT("polygon ((3 1 5, 4 2 4, 5 3 3, 3 1 5))"));
assertEquals("found Z value [5.0] but [ignore_z_value] parameter is [false]", ex.getMessage());
ex = expectThrows(IllegalArgumentException.class,
() -> new WellKnownText(false, randomBoolean()).fromWKT("polygon ((3 1, 4 2, 5 3, 3 1), (0.5 1.5, 2.5 1.5, 2.0 1.0))"));
assertEquals("first and last points of the linear ring must be the same (it must close itself): " +
"lats[0]=1.5 lats[2]=1.0 lons[0]=0.5 lons[2]=2.0", ex.getMessage());
}
}

View File

@ -32,7 +32,7 @@ public class RectangleTests extends BaseGeometryTestCase<Rectangle> {
}
public void testBasicSerialization() throws IOException, ParseException {
WellKnownText wkt = new WellKnownText();
WellKnownText wkt = new WellKnownText(true, true);
assertEquals("bbox (10.0, 20.0, 40.0, 30.0)", wkt.toWKT(new Rectangle(30, 40, 10, 20)));
assertEquals(new Rectangle(30, 40, 10, 20), wkt.fromWKT("bbox (10.0, 20.0, 40.0, 30.0)"));

View File

@ -37,7 +37,7 @@ public final class GeometryParser {
public GeometryParser(boolean rightOrientation, boolean coerce, boolean ignoreZValue) {
geoJsonParser = new GeoJson(rightOrientation, coerce, ignoreZValue);
wellKnownTextParser = new WellKnownText();
wellKnownTextParser = new WellKnownText(coerce, ignoreZValue);
}
/**

View File

@ -111,7 +111,7 @@ public abstract class ExtractedField {
}
private static class GeoShapeField extends FromSource {
private static final WellKnownText wkt = new WellKnownText();
private static final WellKnownText wkt = new WellKnownText(true, true);
GeoShapeField(String alias, String name) {
super(alias, name);

View File

@ -54,7 +54,7 @@ import static org.elasticsearch.xpack.sql.jdbc.JdbcDateUtils.timeAsTime;
*/
final class TypeConverter {
private static WellKnownText WKT = new WellKnownText();
private static WellKnownText WKT = new WellKnownText(true, true);
private TypeConverter() {}

View File

@ -51,7 +51,7 @@ public class JdbcAssert {
private static final IntObjectHashMap<EsType> SQL_TO_TYPE = new IntObjectHashMap<>();
private static final WellKnownText WKT = new WellKnownText();
private static final WellKnownText WKT = new WellKnownText(true, true);
static {
for (EsType type : EsType.values()) {

View File

@ -51,7 +51,7 @@ public class GeoShape implements ToXContentFragment, NamedWriteable {
private static final GeometryParser GEOMETRY_PARSER = new GeometryParser(true, true, true);
private static final WellKnownText WKT_PARSER = new WellKnownText();
private static final WellKnownText WKT_PARSER = new WellKnownText(true, true);
public GeoShape(double lon, double lat) {
shape = new Point(lat, lon);

View File

@ -39,4 +39,13 @@ public class StWkttosqlProcessorTests extends ESTestCase {
siae = expectThrows(SqlIllegalArgumentException.class, () -> procPoint.process("point (10 10"));
assertEquals("Cannot parse [point (10 10] as a geo_shape value", siae.getMessage());
}
public void testCoerce() {
StWkttosqlProcessor proc = new StWkttosqlProcessor();
assertNull(proc.process(null));
Object result = proc.process("POLYGON ((3 1 5, 4 2 4, 5 3 3))");
assertThat(result, instanceOf(GeoShape.class));
GeoShape geoShape = (GeoShape) result;
assertEquals("polygon ((3.0 1.0 5.0, 4.0 2.0 4.0, 5.0 3.0 3.0, 3.0 1.0 5.0))", geoShape.toString());
}
}