From ebdf0d3e3a604133e1a54e79aecd7299e6b7c55e Mon Sep 17 00:00:00 2001 From: shawkins Date: Fri, 21 Sep 2018 17:36:02 -0400 Subject: [PATCH] OLINGO-1294 adding polygon support for multiple interior rings --- .../AtomGeoValueDeserializer.java | 12 ++-- .../serialization/AtomGeoValueSerializer.java | 4 +- .../JsonGeoValueDeserializer.java | 10 +-- .../serialization/JsonGeoValueSerializer.java | 12 ++-- .../olingo/commons/api/edm/geo/Polygon.java | 65 ++++++++++++++++-- .../primitivetype/AbstractGeospatialType.java | 67 +++++++++---------- .../core/edm/primitivetype/EdmGeoTest.java | 31 ++++++++- .../serializer/json/ODataJsonSerializer.java | 4 +- .../core/uri/parser/UriTokenizerTest.java | 5 ++ .../json/ODataJsonDeserializerEntityTest.java | 6 +- 10 files changed, 147 insertions(+), 69 deletions(-) diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomGeoValueDeserializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomGeoValueDeserializer.java index 38add8d77..74ad5c940 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomGeoValueDeserializer.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomGeoValueDeserializer.java @@ -113,8 +113,8 @@ class AtomGeoValueDeserializer { private Polygon polygon(final XMLEventReader reader, final StartElement start, final EdmPrimitiveTypeKind type, final SRID srid) throws XMLStreamException { - List extPoints = null; - List intPoints = null; + LineString extPoints = null; + List intRings = new ArrayList(); boolean foundEndProperty = false; while (reader.hasNext() && !foundEndProperty) { @@ -122,10 +122,12 @@ class AtomGeoValueDeserializer { if (event.isStartElement()) { if (event.asStartElement().getName().equals(Constants.QNAME_POLYGON_EXTERIOR)) { - extPoints = points(reader, event.asStartElement(), type, null); + List points = points(reader, event.asStartElement(), type, null); + extPoints = new LineString(GeoUtils.getDimension(type), srid, points); } if (event.asStartElement().getName().equals(Constants.QNAME_POLYGON_INTERIOR)) { - intPoints = points(reader, event.asStartElement(), type, null); + List points = points(reader, event.asStartElement(), type, null); + intRings.add(new LineString(GeoUtils.getDimension(type), srid, points)); } } @@ -134,7 +136,7 @@ class AtomGeoValueDeserializer { } } - return new Polygon(GeoUtils.getDimension(type), srid, intPoints, extPoints); + return new Polygon(GeoUtils.getDimension(type), srid, intRings, extPoints); } private MultiLineString multiLineString(final XMLEventReader reader, final StartElement start, diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomGeoValueSerializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomGeoValueSerializer.java index 103059760..be5dbde81 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomGeoValueSerializer.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomGeoValueSerializer.java @@ -103,11 +103,11 @@ class AtomGeoValueSerializer { writer.writeEndElement(); writer.writeEndElement(); } - if (!polygon.getInterior().isEmpty()) { + for (int i = 0; i < polygon.getNumberOfInteriorRings(); i++) { writer.writeStartElement(Constants.PREFIX_GML, Constants.ELEM_POLYGON_INTERIOR, Constants.NS_GML); writer.writeStartElement(Constants.PREFIX_GML, Constants.ELEM_POLYGON_LINEARRING, Constants.NS_GML); - points(writer, polygon.getInterior().iterator(), false); + points(writer, polygon.getInterior(i).iterator(), false); writer.writeEndElement(); writer.writeEndElement(); diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonGeoValueDeserializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonGeoValueDeserializer.java index 75aab4ac6..3b967ae84 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonGeoValueDeserializer.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonGeoValueDeserializer.java @@ -127,19 +127,21 @@ class JsonGeoValueDeserializer { } } - List intPoints = null; - if (itor.hasNext()) { + List intRings = new ArrayList(); + while (itor.hasNext()) { final Iterator intItor = itor.next().elements(); if (intItor.hasNext()) { - intPoints = new ArrayList(); + List intPoints = new ArrayList(); while (intItor.hasNext()) { final Iterator mpItor = intItor.next().elements(); intPoints.add(point(mpItor, type, srid)); } + intRings.add(new LineString(GeoUtils.getDimension(type), srid, intPoints)); } } - return new Polygon(GeoUtils.getDimension(type), srid, intPoints, extPoints); + LineString exterior = new LineString(GeoUtils.getDimension(type), srid, extPoints); + return new Polygon(GeoUtils.getDimension(type), srid, intRings, exterior); } private MultiPolygon multiPolygon(final Iterator itor, final EdmPrimitiveTypeKind type, final SRID srid) { diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonGeoValueSerializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonGeoValueSerializer.java index 12ac4f5d4..8801c997b 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonGeoValueSerializer.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonGeoValueSerializer.java @@ -84,14 +84,12 @@ class JsonGeoValueSerializer { } private void polygon(final JsonGenerator jgen, final Polygon polygon) throws IOException { - if (!polygon.getExterior().isEmpty()) { + jgen.writeStartArray(); + lineString(jgen, polygon.getExterior()); + jgen.writeEndArray(); + for (int i = 0; i < polygon.getNumberOfInteriorRings(); i++) { jgen.writeStartArray(); - lineString(jgen, polygon.getExterior()); - jgen.writeEndArray(); - } - if (!polygon.getInterior().isEmpty()) { - jgen.writeStartArray(); - lineString(jgen, polygon.getInterior()); + lineString(jgen, polygon.getInterior(i)); jgen.writeEndArray(); } } diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/geo/Polygon.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/geo/Polygon.java index 7ac468186..02b16b837 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/geo/Polygon.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/geo/Polygon.java @@ -18,6 +18,7 @@ */ package org.apache.olingo.commons.api.edm.geo; +import java.util.Arrays; import java.util.List; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; @@ -27,7 +28,7 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; */ public class Polygon extends Geospatial { - final ComposedGeospatial interior; + final ComposedGeospatial interiorRings; final ComposedGeospatial exterior; /** @@ -37,28 +38,78 @@ public class Polygon extends Geospatial { * @param srid SRID values * @param interior List of interior points * @param exterior List of exterior point + * @deprecated */ public Polygon(final Dimension dimension, final SRID srid, final List interior, final List exterior) { super(dimension, Type.POLYGON, srid); - this.interior = new MultiPoint(dimension, srid, interior); - this.exterior = new MultiPoint(dimension, srid, exterior); + if (interior != null) { + LineString lineString = new LineString(dimension, srid, interior); + this.interiorRings = new MultiLineString(dimension, srid, Arrays.asList(lineString)); + } else { + this.interiorRings = null; + } + this.exterior = new LineString(dimension, srid, exterior); } + + /** + * Creates a new polygon. + * + * @param dimension Dimension of the polygon + * @param srid SRID values + * @param interiors List of interior rings + * @param exterior Ring of exterior point + */ + public Polygon(final Dimension dimension, final SRID srid, + final List interiors, LineString exterior) { + super(dimension, Type.POLYGON, srid); + if (interiors != null) { + this.interiorRings = new MultiLineString(dimension, srid, interiors); + } else { + this.interiorRings = null; + } + this.exterior = exterior; + } /** * Gets interior points. * * @return interior points. + * @deprecated + * @see #getInterior(int) */ public ComposedGeospatial getInterior() { - return interior; + if (interiorRings == null || interiorRings.geospatials.isEmpty()) { + return null; + } + return getInterior(0); + } + + /** + * Get the number of interior rings + * @return number of interior rings + */ + public int getNumberOfInteriorRings() { + if (interiorRings == null) { + return 0; + } + return interiorRings.geospatials.size(); + } + + /** + * Gets the nth interior ring + * @param n + * @return the ring or an exception if no such ring exists + */ + public ComposedGeospatial getInterior(int n) { + return interiorRings.geospatials.get(n); } /** * Gets exterior points. * - * @return exterior points.I + * @return exterior points. */ public ComposedGeospatial getExterior() { return exterior; @@ -83,7 +134,7 @@ public class Polygon extends Geospatial { final Polygon polygon = (Polygon) o; return dimension == polygon.dimension && (srid == null ? polygon.srid == null : srid.equals(polygon.srid)) - && (interior == null ? polygon.interior == null : interior.equals(polygon.interior)) + && (interiorRings == null ? polygon.interiorRings == null : interiorRings.equals(polygon.interiorRings)) && (exterior == null ? polygon.exterior == null : exterior.equals(polygon.exterior)); } @@ -91,7 +142,7 @@ public class Polygon extends Geospatial { public int hashCode() { int result = dimension == null ? 0 : dimension.hashCode(); result = 31 * result + (srid == null ? 0 : srid.hashCode()); - result = 31 * result + (interior == null ? 0 : interior.hashCode()); + result = 31 * result + (interiorRings == null ? 0 : interiorRings.hashCode()); result = 31 * result + (exterior == null ? 0 : exterior.hashCode()); return result; } diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/AbstractGeospatialType.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/AbstractGeospatialType.java index b712f9f06..d4e05e9a4 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/AbstractGeospatialType.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/AbstractGeospatialType.java @@ -26,6 +26,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; +import org.apache.olingo.commons.api.edm.geo.ComposedGeospatial; import org.apache.olingo.commons.api.edm.geo.Geospatial; import org.apache.olingo.commons.api.edm.geo.Geospatial.Dimension; import org.apache.olingo.commons.api.edm.geo.Geospatial.Type; @@ -176,16 +177,20 @@ public abstract class AbstractGeospatialType extends Singl final String[] first = polygon.split("\\),\\("); - final List interior = new ArrayList(); - for (final String pointCoo : split(first[0].substring(1, first[0].length()), ',')) { - interior.add(newPoint(null, pointCoo, isNullable, maxLength, precision, scale, isUnicode)); + final List interiorRings = new ArrayList(); + for (int i = 0; i < first.length -1; i++) { + List interior = new ArrayList(); + for (final String pointCoo : split(first[i].substring(i==0?1:0, first[i].length()), ',')) { + interior.add(newPoint(null, pointCoo, isNullable, maxLength, precision, scale, isUnicode)); + } + interiorRings.add(new LineString(dimension, srid, interior)); } final List exterior = new ArrayList(); - for (final String pointCoo : split(first[1].substring(0, first[1].length() - 1), ',')) { + for (final String pointCoo : split(first[first.length -1].substring(0, first[first.length -1].length() - 1), ',')) { exterior.add(newPoint(null, pointCoo, isNullable, maxLength, precision, scale, isUnicode)); } - return new Polygon(dimension, srid, interior, exterior); + return new Polygon(dimension, srid, interiorRings, new LineString(dimension, srid, exterior)); } protected Polygon stringToPolygon(final String value, final Boolean isNullable, final Integer maxLength, @@ -343,21 +348,17 @@ public abstract class AbstractGeospatialType extends Singl return result.append(")'").toString(); } - private String lineString(final LineString lineString, final Boolean isNullable, - final Integer maxLength, final Integer precision, final Integer scale, final Boolean isUnicode) - throws EdmPrimitiveTypeException { - - final StringBuilder result = new StringBuilder(); - - for (final Iterator itor = lineString.iterator(); itor.hasNext();) { + private StringBuilder appendPoints(final ComposedGeospatial points, final Boolean isNullable, + final Integer maxLength, final Integer precision, final Integer scale, final Boolean isUnicode, + final StringBuilder result) throws EdmPrimitiveTypeException { + for (final Iterator itor = points.iterator(); itor.hasNext();) { result.append(point(itor.next(), isNullable, maxLength, precision, scale, isUnicode)); if (itor.hasNext()) { result.append(','); } } - - return result.toString(); - } + return result; +} protected String toString(final LineString lineString, final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException { @@ -366,10 +367,10 @@ public abstract class AbstractGeospatialType extends Singl throw new EdmPrimitiveTypeException("The value '" + lineString + "' is not valid."); } - return toStringBuilder(lineString.getSrid()). + StringBuilder builder = toStringBuilder(lineString.getSrid()). append(reference.getSimpleName()). - append('('). - append(lineString(lineString, isNullable, maxLength, precision, scale, isUnicode)). + append('('); + return appendPoints(lineString, isNullable, maxLength, precision, scale, isUnicode, builder). append(")'").toString(); } @@ -385,8 +386,8 @@ public abstract class AbstractGeospatialType extends Singl append('('); for (final Iterator itor = multiLineString.iterator(); itor.hasNext();) { - result.append('('). - append(lineString(itor.next(), isNullable, maxLength, precision, scale, isUnicode)). + result.append('('); + appendPoints(itor.next(), isNullable, maxLength, precision, scale, isUnicode, result). append(')'); if (itor.hasNext()) { result.append(','); @@ -402,20 +403,14 @@ public abstract class AbstractGeospatialType extends Singl final StringBuilder result = new StringBuilder(); + for (int i = 0; i < polygon.getNumberOfInteriorRings(); i++) { + result.append('('); + appendPoints(polygon.getInterior(i), isNullable, maxLength, precision, scale, isUnicode, result); + result.append("),"); + } + result.append('('); - for (final Iterator itor = polygon.getInterior().iterator(); itor.hasNext();) { - result.append(point(itor.next(), isNullable, maxLength, precision, scale, isUnicode)); - if (itor.hasNext()) { - result.append(','); - } - } - result.append("),("); - for (final Iterator itor = polygon.getExterior().iterator(); itor.hasNext();) { - result.append(point(itor.next(), isNullable, maxLength, precision, scale, isUnicode)); - if (itor.hasNext()) { - result.append(','); - } - } + appendPoints(polygon.getExterior(), isNullable, maxLength, precision, scale, isUnicode, result); return result.append(')').toString(); } @@ -490,14 +485,14 @@ public abstract class AbstractGeospatialType extends Singl case GeographyLineString: case GeometryLineString: - result.append(lineString((LineString) item, isNullable, maxLength, precision, scale, isUnicode)); + appendPoints((LineString) item, isNullable, maxLength, precision, scale, isUnicode, result); break; case GeographyMultiLineString: case GeometryMultiLineString: for (final Iterator itor = ((MultiLineString) item).iterator(); itor.hasNext();) { - result.append('('). - append(lineString(itor.next(), isNullable, maxLength, precision, scale, isUnicode)). + result.append('('); + appendPoints(itor.next(), isNullable, maxLength, precision, scale, isUnicode, result). append(')'); if (itor.hasNext()) { result.append(','); diff --git a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmGeoTest.java b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmGeoTest.java index 28f31e0aa..449fa42c6 100644 --- a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmGeoTest.java +++ b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmGeoTest.java @@ -120,7 +120,7 @@ public class EdmGeoTest extends PrimitiveTypeBaseTest { valueOfString(input, null, null, null, null, null, Polygon.class); assertNotNull(polygon); assertEquals("0", polygon.getSrid().toString()); - Iterator itor = polygon.getInterior().iterator(); + Iterator itor = polygon.getInterior(0).iterator(); assertEquals(1, itor.next().getX(), 0); assertEquals(1, itor.next().getY(), 0); itor = polygon.getExterior().iterator(); @@ -130,6 +130,31 @@ public class EdmGeoTest extends PrimitiveTypeBaseTest { assertEquals(input, EdmGeographyPolygon.getInstance().valueToString(polygon, null, null, null, null, null)); } + + @Test + public void polygonMultipleHoles() throws EdmPrimitiveTypeException { + final String input = "geography'SRID=4326;Polygon((1.0 1.0,1.0 1.0),(2.0 2.0,2.0 2.0)" + + ",(1.0 1.0,2.0 2.0,3.0 3.0,1.0 1.0))'"; + + expectContentErrorInValueOfString(EdmGeometryPolygon.getInstance(), input); + + final Polygon polygon = EdmGeographyPolygon.getInstance(). + valueOfString(input, null, null, null, null, null, Polygon.class); + assertNotNull(polygon); + assertEquals("4326", polygon.getSrid().toString()); + Iterator itor = polygon.getInterior(0).iterator(); + assertEquals(1, itor.next().getX(), 0); + assertEquals(1, itor.next().getY(), 0); + itor = polygon.getInterior(1).iterator(); + assertEquals(2, itor.next().getX(), 0); + assertEquals(2, itor.next().getY(), 0); + itor = polygon.getExterior().iterator(); + itor.next(); + assertEquals(2, itor.next().getX(), 0); + assertEquals(3, itor.next().getY(), 0); + + assertEquals(input, EdmGeographyPolygon.getInstance().valueToString(polygon, null, null, null, null, null)); + } @Test public void multiPolygon() throws EdmPrimitiveTypeException { @@ -145,8 +170,8 @@ public class EdmGeoTest extends PrimitiveTypeBaseTest { assertNotNull(multiPolygon); assertEquals("0", multiPolygon.getSrid().toString()); final Iterator itor = multiPolygon.iterator(); - assertEquals(1, itor.next().getInterior().iterator().next().getX(), 0); - assertEquals(1, itor.next().getInterior().iterator().next().getX(), 0); + assertEquals(1, itor.next().getInterior(0).iterator().next().getX(), 0); + assertEquals(1, itor.next().getInterior(0).iterator().next().getX(), 0); assertEquals(input, EdmGeometryMultiPolygon.getInstance(). valueToString(multiPolygon, null, null, null, null, null)); diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java index 43222106d..40435aea9 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java @@ -1060,9 +1060,9 @@ public class ODataJsonSerializer extends AbstractODataSerializer { json.writeStartArray(); writeGeoPoints(json, polygon.getExterior()); json.writeEndArray(); - if (!polygon.getInterior().isEmpty()) { + for (int i = 0; i < polygon.getNumberOfInteriorRings(); i++) { json.writeStartArray(); - writeGeoPoints(json, polygon.getInterior()); + writeGeoPoints(json, polygon.getInterior(i)); json.writeEndArray(); } } diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java index 23bf1d10e..e47f6c8e5 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java @@ -603,6 +603,11 @@ public class UriTokenizerTest { public void geoPolygon() { assertTrue(new UriTokenizer("geography'SRID=4326;Polygon((0 0,1 0,0 1,0 0))'").next(TokenKind.GeographyPolygon)); assertTrue(new UriTokenizer("geometry'SRID=0;Polygon((0 0,1 0,0 1,0 0))'").next(TokenKind.GeometryPolygon)); + assertTrue(new UriTokenizer("geometry'SRID=0;Polygon((1 1,2 1,2 2,1 2,1 1),(0 0,4 0,4 4,0 4,0 0))'") + .next(TokenKind.GeometryPolygon)); + assertTrue(new UriTokenizer( + "geometry'SRID=0;Polygon((0 0,1 1,2 2,0 0),(1 1,2 1,2 2,1 2,1 1),(0 0,4 0,4 4,0 4,0 0))'") + .next(TokenKind.GeometryPolygon)); wrongToken(TokenKind.GeometryPolygon, "geometry'SRID=0;Polygon((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1))'", 'x'); diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java index 1eb96a93b..fecae8015 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java @@ -1036,13 +1036,13 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe Polygon polygon = (Polygon) entity.getProperties().get(0).getValue(); assertEquals(Geospatial.Dimension.GEOMETRY, polygon.getDimension()); assertEquals(0, polygon.getExterior().iterator().next().getX(), 0); - assertEquals(1, polygon.getInterior().iterator().next().getY(), 0); + assertEquals(1, polygon.getInterior(0).iterator().next().getY(), 0); entity = deserialize("{\"" + entityType.getPropertyNames().get(0) + "\":{" + "\"type\":\"Polygon\",\"coordinates\":[[[0,0],[3,0],[3,3],[0,3],[0,0]]]}}", entityType); polygon = (Polygon) entity.getProperties().get(0).getValue(); - assertTrue(polygon.getInterior().isEmpty()); + assertEquals(0, polygon.getNumberOfInteriorRings()); expectException("{\"" + entityType.getPropertyNames().get(0) + "\":{" + "\"type\":\"Polygon\",\"coordinates\":{\"ext\":[[0,0],[3,0],[0,3],[0,0]]}}}", entityType, @@ -1070,7 +1070,7 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe + "[[[0.0,0.0],[30.0,0.0],[0.0,30.0],[0.0,0.0]]]]}}", entityType); final MultiPolygon multiPolygon = (MultiPolygon) entity.getProperties().get(0).getValue(); - assertEquals(1, multiPolygon.iterator().next().getInterior().iterator().next().getX(), 0); + assertEquals(1, multiPolygon.iterator().next().getInterior(0).iterator().next().getX(), 0); expectException("{\"" + entityType.getPropertyNames().get(0) + "\":{" + "\"type\":\"MultiPolygon\",\"coordinates\":[{\"first\":[[[0,0],[3,0],[3,3],[0,3],[0,0]]]}]}}", entityType,