From 327bc272e5ef863a74488a2e73a37e8da0d07ac3 Mon Sep 17 00:00:00 2001
From: Neelesh Thakur <NThakur4@slb.com>
Date: Sun, 14 Mar 2021 14:28:39 -0500
Subject: [PATCH] add support for featurecollection

---
 .../osdu/indexer/model/geojson/Feature.java   |  26 +
 .../model/geojson/FeatureCollection.java      |  31 +
 .../indexer/model/geojson/GeoJsonObject.java  |  22 +
 .../osdu/indexer/model/geojson/Geometry.java  |  31 +
 .../model/geojson/GeometryCollection.java     |  23 +
 .../indexer/model/geojson/LineString.java     |  11 +
 .../model/geojson/MultiLineString.java        |  13 +
 .../indexer/model/geojson/MultiPoint.java     |  11 +
 .../indexer/model/geojson/MultiPolygon.java   |  18 +
 .../osdu/indexer/model/geojson/Point.java     |  21 +
 .../osdu/indexer/model/geojson/Polygon.java   |  59 ++
 .../osdu/indexer/model/geojson/Position.java  |  56 +
 .../jackson/FeatureCollectionSerializer.java  |  67 ++
 .../geojson/jackson/PositionDeserializer.java |  53 +
 .../geojson/jackson/PositionSerializer.java   |  22 +
 .../service/AttributeParsingServiceImpl.java  |   7 +-
 .../indexer/util/parser/GeoShapeParser.java   |  53 +-
 .../AttributeParsingServiceImplTest.java      |   2 +-
 .../util/parser/GeoShapeParserTest.java       |  62 +-
 .../resources/testData/index_records_3.json   | 977 ++++++++++--------
 20 files changed, 1039 insertions(+), 526 deletions(-)
 create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Feature.java
 create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/FeatureCollection.java
 create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeoJsonObject.java
 create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Geometry.java
 create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeometryCollection.java
 create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/LineString.java
 create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiLineString.java
 create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPoint.java
 create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPolygon.java
 create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Point.java
 create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Polygon.java
 create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Position.java
 create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/FeatureCollectionSerializer.java
 create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionDeserializer.java
 create mode 100644 indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionSerializer.java

diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Feature.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Feature.java
new file mode 100644
index 000000000..7c429e716
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Feature.java
@@ -0,0 +1,26 @@
+package org.opengroup.osdu.indexer.model.geojson;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Data
+public class Feature extends GeoJsonObject {
+
+    @JsonInclude()
+    private Map<String, Object> properties = new HashMap<String, Object>();
+    @JsonInclude()
+    private GeoJsonObject geometry;
+    private String id;
+
+    public void setProperty(String key, Object value) {
+        properties.put(key, value);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T getProperty(String key) {
+        return (T) properties.get(key);
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/FeatureCollection.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/FeatureCollection.java
new file mode 100644
index 000000000..c8c84a76a
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/FeatureCollection.java
@@ -0,0 +1,31 @@
+package org.opengroup.osdu.indexer.model.geojson;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import lombok.Data;
+import org.opengroup.osdu.indexer.model.geojson.jackson.FeatureCollectionSerializer;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+@Data
+@JsonSerialize(using = FeatureCollectionSerializer.class)
+public class FeatureCollection extends GeoJsonObject implements Iterable<Feature> {
+
+    private List<Feature> features = new ArrayList<Feature>();
+
+    public FeatureCollection add(Feature feature) {
+        features.add(feature);
+        return this;
+    }
+
+    public void addAll(Collection<Feature> features) {
+        this.features.addAll(features);
+    }
+
+    @Override
+    public Iterator<Feature> iterator() {
+        return features.iterator();
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeoJsonObject.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeoJsonObject.java
new file mode 100644
index 000000000..9ba2ee3f0
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeoJsonObject.java
@@ -0,0 +1,22 @@
+package org.opengroup.osdu.indexer.model.geojson;
+
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+import lombok.Data;
+
+@Data
+@JsonTypeInfo(property = "type", use = Id.NAME)
+@JsonSubTypes({ @Type(Feature.class), @Type(Polygon.class), @Type(MultiPolygon.class), @Type(FeatureCollection.class),
+		@Type(Point.class), @Type(MultiPoint.class), @Type(MultiLineString.class), @Type(LineString.class),
+                @Type(GeometryCollection.class) })
+@JsonInclude(Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public abstract class GeoJsonObject implements Serializable {
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Geometry.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Geometry.java
new file mode 100644
index 000000000..f061161d4
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Geometry.java
@@ -0,0 +1,31 @@
+package org.opengroup.osdu.indexer.model.geojson;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class Geometry<T> extends GeoJsonObject {
+
+    protected List<T> coordinates = new ArrayList<T>();
+
+    public Geometry() {
+    }
+
+    public Geometry(T... elements) {
+        for (T coordinate : elements) {
+            coordinates.add(coordinate);
+        }
+    }
+
+    public Geometry<T> add(T elements) {
+        coordinates.add(elements);
+        return this;
+    }
+
+    public List<T> getCoordinates() {
+        return coordinates;
+    }
+
+    public void setCoordinates(List<T> coordinates) {
+        this.coordinates = coordinates;
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeometryCollection.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeometryCollection.java
new file mode 100644
index 000000000..a4159116a
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/GeometryCollection.java
@@ -0,0 +1,23 @@
+package org.opengroup.osdu.indexer.model.geojson;
+
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+@Data
+public class GeometryCollection extends GeoJsonObject implements Iterable<GeoJsonObject> {
+
+    private List<GeoJsonObject> geometries = new ArrayList<GeoJsonObject>();
+
+    @Override
+    public Iterator<GeoJsonObject> iterator() {
+        return geometries.iterator();
+    }
+
+    public GeometryCollection add(GeoJsonObject geometry) {
+        geometries.add(geometry);
+        return this;
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/LineString.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/LineString.java
new file mode 100644
index 000000000..a2692ec75
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/LineString.java
@@ -0,0 +1,11 @@
+package org.opengroup.osdu.indexer.model.geojson;
+
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor
+public class LineString extends MultiPoint {
+
+    public LineString(Position... points) {
+        super(points);
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiLineString.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiLineString.java
new file mode 100644
index 000000000..701dabd59
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiLineString.java
@@ -0,0 +1,13 @@
+package org.opengroup.osdu.indexer.model.geojson;
+
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@NoArgsConstructor
+public class MultiLineString extends Geometry<List<Position>> {
+
+    public MultiLineString(List<Position> line) {
+        add(line);
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPoint.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPoint.java
new file mode 100644
index 000000000..4c44e0844
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPoint.java
@@ -0,0 +1,11 @@
+package org.opengroup.osdu.indexer.model.geojson;
+
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor
+public class MultiPoint extends Geometry<Position> {
+
+    public MultiPoint(Position... points) {
+        super(points);
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPolygon.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPolygon.java
new file mode 100644
index 000000000..f223b2094
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/MultiPolygon.java
@@ -0,0 +1,18 @@
+package org.opengroup.osdu.indexer.model.geojson;
+
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@NoArgsConstructor
+public class MultiPolygon extends Geometry<List<List<Position>>> {
+
+    public MultiPolygon(Polygon polygon) {
+        add(polygon);
+    }
+
+    public MultiPolygon add(Polygon polygon) {
+        coordinates.add(polygon.getCoordinates());
+        return this;
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Point.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Point.java
new file mode 100644
index 000000000..429b08de2
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Point.java
@@ -0,0 +1,21 @@
+package org.opengroup.osdu.indexer.model.geojson;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Point extends GeoJsonObject {
+
+    private Position coordinates;
+
+    public Point(double longitude, double latitude) {
+        coordinates = new Position(longitude, latitude);
+    }
+
+    public Point(double longitude, double latitude, double altitude) {
+        coordinates = new Position(longitude, latitude, altitude);
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Polygon.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Polygon.java
new file mode 100644
index 000000000..f1f9e0011
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Polygon.java
@@ -0,0 +1,59 @@
+package org.opengroup.osdu.indexer.model.geojson;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.NoArgsConstructor;
+
+import java.util.Arrays;
+import java.util.List;
+
+@NoArgsConstructor
+public class Polygon extends Geometry<List<Position>> {
+
+    public Polygon(List<Position> polygon) {
+        add(polygon);
+    }
+
+    public Polygon(Position... polygon) {
+        add(Arrays.asList(polygon));
+    }
+
+    public void setExteriorRing(List<Position> points) {
+        if (coordinates.isEmpty()) {
+            coordinates.add(0, points);
+        } else {
+            coordinates.set(0, points);
+        }
+    }
+
+    @JsonIgnore
+    public List<Position> getExteriorRing() {
+        assertExteriorRing();
+        return coordinates.get(0);
+    }
+
+    @JsonIgnore
+    public List<List<Position>> getInteriorRings() {
+        assertExteriorRing();
+        return coordinates.subList(1, coordinates.size());
+    }
+
+    public List<Position> getInteriorRing(int index) {
+        assertExteriorRing();
+        return coordinates.get(1 + index);
+    }
+
+    public void addInteriorRing(List<Position> points) {
+        assertExteriorRing();
+        coordinates.add(points);
+    }
+
+    public void addInteriorRing(Position... points) {
+        assertExteriorRing();
+        coordinates.add(Arrays.asList(points));
+    }
+
+    private void assertExteriorRing() {
+        if (coordinates.isEmpty())
+            throw new RuntimeException("No exterior ring defined");
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Position.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Position.java
new file mode 100644
index 000000000..1c9a58409
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/Position.java
@@ -0,0 +1,56 @@
+package org.opengroup.osdu.indexer.model.geojson;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.opengroup.osdu.indexer.model.geojson.jackson.PositionDeserializer;
+import org.opengroup.osdu.indexer.model.geojson.jackson.PositionSerializer;
+
+import java.io.Serializable;
+
+@Getter
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+@AllArgsConstructor
+@JsonDeserialize(using = PositionDeserializer.class)
+@JsonSerialize(using = PositionSerializer.class)
+public class Position implements Serializable {
+
+    private double longitude;
+    private double latitude;
+    @JsonIgnore
+    private double altitude = Double.NaN;
+
+    public Position(double longitude, double latitude) {
+        this.setLongitude(longitude);
+        this.setLatitude(latitude);
+    }
+
+    public void setLongitude(double longitude) {
+        if (Double.isNaN(longitude))
+            throw new IllegalArgumentException("latitude must be number");
+        if (longitude > 180 || longitude < -180)
+            throw new IllegalArgumentException("'longitude' value is out of the range [-180, 180]");
+        this.longitude = longitude;
+    }
+
+    public void setLatitude(double latitude) {
+        if (Double.isNaN(latitude))
+            throw new IllegalArgumentException("latitude must be number");
+        if (latitude > 90 || latitude < -90)
+            throw new IllegalArgumentException("latitude value is out of the range [-90, 90]");
+        this.latitude = latitude;
+    }
+
+    public void setAltitude(double altitude) {
+        this.altitude = altitude;
+    }
+
+    public boolean hasAltitude() {
+        return !Double.isNaN(altitude);
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/FeatureCollectionSerializer.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/FeatureCollectionSerializer.java
new file mode 100644
index 000000000..248202090
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/FeatureCollectionSerializer.java
@@ -0,0 +1,67 @@
+package org.opengroup.osdu.indexer.model.geojson.jackson;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
+import lombok.Data;
+import org.opengroup.osdu.indexer.model.geojson.*;
+
+import java.io.IOException;
+
+@Data
+public class FeatureCollectionSerializer extends JsonSerializer<FeatureCollection> {
+
+    @Override
+    public void serialize(FeatureCollection value, JsonGenerator jsonGenerator, SerializerProvider provider) throws IOException {
+        jsonGenerator.writeStartObject();
+        jsonGenerator.writeStringField("type", "geometrycollection");
+
+        jsonGenerator.writeArrayFieldStart("geometries");
+        for (Feature feature : value.getFeatures()) {
+            jsonGenerator.writeStartObject();
+            if (feature.getGeometry() instanceof GeometryCollection) {
+                GeometryCollection geometryCollection = (GeometryCollection) feature.getGeometry();
+                for (GeoJsonObject shape : geometryCollection.getGeometries()) {
+                    serializeGeoShape(shape, jsonGenerator);
+                }
+            } else {
+                serializeGeoShape(feature.getGeometry(), jsonGenerator);
+            }
+            jsonGenerator.writeEndObject();
+        }
+        jsonGenerator.writeEndArray();
+
+        jsonGenerator.writeEndObject();
+    }
+
+    @Override
+    public void serializeWithType(FeatureCollection value, JsonGenerator jsonGenerator, SerializerProvider provider, TypeSerializer typeSerializer)
+            throws IOException, JsonProcessingException {
+
+        serialize(value, jsonGenerator, provider);
+    }
+
+    private void serializeGeoShape(GeoJsonObject geoJsonObject, JsonGenerator jsonGenerator) throws IOException {
+        if (geoJsonObject instanceof Point) {
+            jsonGenerator.writeStringField("type", "point");
+            jsonGenerator.writeObjectField("coordinates", ((Point) geoJsonObject).getCoordinates());
+        } else if (geoJsonObject instanceof LineString) {
+            jsonGenerator.writeStringField("type", "linestring");
+            jsonGenerator.writeObjectField("coordinates", ((LineString) geoJsonObject).getCoordinates());
+        } else if (geoJsonObject instanceof Polygon) {
+            jsonGenerator.writeStringField("type", "polygon");
+            jsonGenerator.writeObjectField("coordinates", ((Polygon) geoJsonObject).getCoordinates());
+        } else if (geoJsonObject instanceof MultiPoint) {
+            jsonGenerator.writeStringField("type", "multipoint");
+            jsonGenerator.writeObjectField("coordinates", ((MultiPoint) geoJsonObject).getCoordinates());
+        } else if (geoJsonObject instanceof MultiLineString) {
+            jsonGenerator.writeStringField("type", "multilinestring");
+            jsonGenerator.writeObjectField("coordinates", ((MultiLineString) geoJsonObject).getCoordinates());
+        } else if (geoJsonObject instanceof MultiPolygon) {
+            jsonGenerator.writeStringField("type", "multipolygon");
+            jsonGenerator.writeObjectField("coordinates", ((MultiPolygon) geoJsonObject).getCoordinates());
+        }
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionDeserializer.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionDeserializer.java
new file mode 100644
index 000000000..d837e09e2
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionDeserializer.java
@@ -0,0 +1,53 @@
+package org.opengroup.osdu.indexer.model.geojson.jackson;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import org.opengroup.osdu.indexer.model.geojson.Position;
+
+import java.io.IOException;
+
+public class PositionDeserializer extends JsonDeserializer<Position> {
+
+    @Override
+    public Position deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
+        if (jsonParser.isExpectedStartArrayToken()) {
+            return deserializeArray(jsonParser, context);
+        }
+        throw context.mappingException(Position.class);
+    }
+
+    protected Position deserializeArray(JsonParser jsonParser, DeserializationContext context) throws IOException {
+        Position node = new Position();
+        node.setLongitude(extractDouble(jsonParser, context, false));
+        node.setLatitude(extractDouble(jsonParser, context, false));
+        node.setAltitude(extractDouble(jsonParser, context, true));
+        return node;
+    }
+
+    private double extractDouble(JsonParser jsonParser, DeserializationContext context, boolean optional) throws IOException {
+        JsonToken token = jsonParser.nextToken();
+        if (token == null) {
+            if (optional)
+                return Double.NaN;
+            else
+                throw context.mappingException("Unexpected end-of-input when binding data into Position");
+        } else {
+            switch (token) {
+                case END_ARRAY:
+                    if (optional)
+                        return Double.NaN;
+                    else
+                        throw context.mappingException("Unexpected end-of-input when binding data into Position");
+                case VALUE_NUMBER_FLOAT:
+                    return jsonParser.getDoubleValue();
+                case VALUE_NUMBER_INT:
+                    return jsonParser.getLongValue();
+                default:
+                    throw context.mappingException(
+                            "Unexpected token (" + token.name() + ") when binding data into Position");
+            }
+        }
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionSerializer.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionSerializer.java
new file mode 100644
index 000000000..909482d69
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/geojson/jackson/PositionSerializer.java
@@ -0,0 +1,22 @@
+package org.opengroup.osdu.indexer.model.geojson.jackson;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import org.opengroup.osdu.indexer.model.geojson.Position;
+
+import java.io.IOException;
+
+public class PositionSerializer extends JsonSerializer<Position> {
+
+    @Override
+    public void serialize(Position value, JsonGenerator jsonGenerator, SerializerProvider provider) throws IOException {
+        jsonGenerator.writeStartArray();
+        jsonGenerator.writeNumber(value.getLongitude());
+        jsonGenerator.writeNumber(value.getLatitude());
+        if (value.hasAltitude()) {
+            jsonGenerator.writeNumber(value.getAltitude());
+        }
+        jsonGenerator.writeEndArray();
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImpl.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImpl.java
index fae0b4e6f..733408ab3 100644
--- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImpl.java
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImpl.java
@@ -25,6 +25,7 @@ import org.opengroup.osdu.core.common.model.indexer.IndexSchema;
 import org.opengroup.osdu.core.common.model.indexer.IndexingStatus;
 import org.opengroup.osdu.core.common.model.indexer.JobStatus;
 import org.opengroup.osdu.core.common.Constants;
+import org.opengroup.osdu.indexer.model.geojson.FeatureCollection;
 import org.opengroup.osdu.indexer.util.parser.BooleanParser;
 import org.opengroup.osdu.indexer.util.parser.DateTimeParser;
 import org.opengroup.osdu.indexer.util.parser.GeoShapeParser;
@@ -185,7 +186,7 @@ public class AttributeParsingServiceImpl implements IAttributeParsingService {
                 dataMap.put(DATA_GEOJSON_TAG, geometry);
             }
         } catch (JsonSyntaxException | IllegalArgumentException e) {
-            String parsingError = String.format("geopoint parsing error: %s attribute: %s | value: %s", e.getMessage(), attributeName, attributeVal);
+            String parsingError = String.format("geo-point parsing error: %s attribute: %s | value: %s", e.getMessage(), attributeName, attributeVal);
             jobStatus.addOrUpdateRecordStatus(recordId, IndexingStatus.WARN, HttpStatus.SC_BAD_REQUEST, parsingError, String.format("record-id: %s | %s", recordId, parsingError));
         }
     }
@@ -199,9 +200,9 @@ public class AttributeParsingServiceImpl implements IAttributeParsingService {
 
             if (geoJsonMap == null || geoJsonMap.isEmpty()) return;
 
-            this.geoShapeParser.parseGeoJson(geoJsonMap);
+            Map<String, Object> parsedShape = this.geoShapeParser.parseGeoJson(geoJsonMap);
 
-            dataMap.put(attributeName, geoJsonMap);
+            dataMap.put(attributeName, parsedShape);
         } catch (JsonSyntaxException | IllegalArgumentException e) {
             String parsingError = String.format("geo-json shape parsing error: %s attribute: %s", e.getMessage(), attributeName);
             jobStatus.addOrUpdateRecordStatus(recordId, IndexingStatus.WARN, HttpStatus.SC_BAD_REQUEST, parsingError, String.format("record-id: %s | %s", recordId, parsingError));
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParser.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParser.java
index 9532e498b..8bd6ec834 100644
--- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParser.java
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParser.java
@@ -14,55 +14,36 @@
 
 package org.opengroup.osdu.indexer.util.parser;
 
-import org.elasticsearch.ElasticsearchParseException;
-import org.elasticsearch.common.bytes.BytesReference;
-import org.elasticsearch.common.geo.builders.ShapeBuilder;
-import org.elasticsearch.common.geo.parsers.ShapeParser;
-import org.elasticsearch.common.xcontent.DeprecationHandler;
-import org.elasticsearch.common.xcontent.NamedXContentRegistry;
-import org.elasticsearch.common.xcontent.XContentBuilder;
-import org.elasticsearch.common.xcontent.XContentParser;
-import org.elasticsearch.common.xcontent.json.JsonXContent;
-import org.locationtech.spatial4j.exception.InvalidShapeException;
-import org.locationtech.spatial4j.shape.Shape;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.exc.InvalidTypeIdException;
 import org.opengroup.osdu.core.common.search.Preconditions;
+import org.opengroup.osdu.indexer.model.geojson.FeatureCollection;
 import org.springframework.stereotype.Component;
 import org.springframework.web.context.annotation.RequestScope;
 
-import java.io.IOException;
 import java.util.Map;
 
 @Component
 @RequestScope
 public class GeoShapeParser {
 
-    public String parseGeoJson(Map<String, Object> geoShapeObject) {
+    private ObjectMapper mapper = new ObjectMapper();
 
-        Preconditions.checkNotNull(geoShapeObject, "geoShapeObject cannot be null");
+    public Map<String, Object> parseGeoJson(Map<String, Object> objectMap) {
 
-        try {
-            // use elasticsearch's ShapeParser to validate shape
-            ShapeBuilder shapeBuilder = getShapeBuilderFromObject(geoShapeObject);
-            Shape shape = shapeBuilder.buildS4J();
-            if (shape == null) {
-                throw new IllegalArgumentException("unable to parse shape");
-            }
+        Preconditions.checkNotNull(objectMap, "geoShapeObject cannot be null");
+        if (objectMap.isEmpty()) throw new IllegalArgumentException("shape not included");
 
-            return shapeBuilder.toString().replaceAll("\\r", "").replaceAll("\\n", "");
-        } catch (ElasticsearchParseException | InvalidShapeException | IOException e) {
-            throw new IllegalArgumentException(e.getMessage(), e);
+        try {
+            FeatureCollection collection = mapper.readValue(mapper.writeValueAsString(objectMap), FeatureCollection.class);
+            return mapper.readValue(mapper.writeValueAsString(collection), new TypeReference<Map<String, Object>>() {
+            });
+        } catch (InvalidTypeIdException e) {
+            throw new IllegalArgumentException("must be a valid FeatureCollection");
+        } catch (JsonProcessingException e) {
+            throw new IllegalArgumentException("unable to parse FeatureCollection");
         }
     }
-
-    private ShapeBuilder getShapeBuilderFromObject(Map<String, Object> object) throws IOException {
-        XContentBuilder contentBuilder = JsonXContent.contentBuilder().value(object);
-
-        XContentParser parser = JsonXContent.jsonXContent.createParser(
-                NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION,
-                BytesReference.bytes(contentBuilder).streamInput()
-        );
-
-        parser.nextToken();
-        return ShapeParser.parse(parser);
-    }
 }
\ No newline at end of file
diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImplTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImplTest.java
index 5db76eb05..67362f02c 100644
--- a/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImplTest.java
+++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/AttributeParsingServiceImplTest.java
@@ -321,7 +321,7 @@ public class AttributeParsingServiceImplTest {
         Map<String, Object> storageData = new HashMap<>();
         storageData.put("location", parseJson(shapeJson));
 
-        when(this.geoShapeParser.parseGeoJson(storageData)).thenReturn("");
+        when(this.geoShapeParser.parseGeoJson(storageData)).thenReturn(new HashMap<>());
 
         Map<String, Object> dataMap = new HashMap<>();
 
diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParserTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParserTest.java
index 8c1d36fe9..2e34f70c9 100644
--- a/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParserTest.java
+++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/parser/GeoShapeParserTest.java
@@ -29,8 +29,7 @@ import java.util.Map;
 import java.util.function.Function;
 
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
+import static org.junit.Assert.*;
 
 @RunWith(SpringRunner.class)
 public class GeoShapeParserTest {
@@ -45,124 +44,129 @@ public class GeoShapeParserTest {
     public void should_throwException_provided_emptyGeoJson() {
         String shapeJson = "{}";
 
-        this.validateInput(this.sut::parseGeoJson, shapeJson, "shape type not included");
+        this.validateInput(this.sut::parseGeoJson, shapeJson, "shape not included");
     }
 
     @Test
     public void should_throwException_parseInvalidPoint() {
-        String shapeJson = "{\"type\":\"Point\",\"coordinates\":[-205.01621,39.57422]}";
+        String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[-205.01621,39.57422]}}]}";
 
-        this.validateInput(this.sut::parseGeoJson, shapeJson, "Bad X value -205.01621 is not in boundary Rect(minX=-180.0,maxX=180.0,minY=-90.0,maxY=90.0)");
+        this.validateInput(this.sut::parseGeoJson, shapeJson, "unable to parse FeatureCollection");
     }
 
     @Test
     public void should_throwException_parseInvalidPoint_NaN() {
-        String shapeJson = "{\"type\":\"Point\",\"coordinates\":[-205.01621,NaN]}";
+        String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[-205.01621,NaN]}}]}";
 
-        this.validateInput(this.sut::parseGeoJson, shapeJson, "geo coordinates must be numbers");
+        this.validateInput(this.sut::parseGeoJson, shapeJson, "unable to parse FeatureCollection");
     }
 
     @Test
     public void should_throwException_parseInvalidPoint_missingLatitude() {
-        String shapeJson = "{\"type\":\"Point\",\"coordinates\":[-205.01621,\"\"]}";
+        String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[-105.01621]}}]}";
 
-        this.validateInput(this.sut::parseGeoJson, shapeJson, "geo coordinates must be numbers");
+        this.validateInput(this.sut::parseGeoJson, shapeJson, "unable to parse FeatureCollection");
     }
 
     @Test
     public void should_throwException_missingMandatoryAttribute() {
-        String shapeJson = "{\"mistype\":\"Point\",\"coordinates\":[-205.01621,39.57422]}";
+        String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"mistype\":\"Point\",\"coordinates\":[-205.01621,39.57422]}}]}";
 
-        this.validateInput(this.sut::parseGeoJson, shapeJson, "shape type not included");
+        this.validateInput(this.sut::parseGeoJson, shapeJson, "must be a valid FeatureCollection");
     }
 
     @Test
     public void should_throwException_parseInvalidShape() {
-        String shapeJson = "{\"type\":\"InvalidShape\",\"coordinates\":[-105.01621,39.57422]}";
+        String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"InvalidShape\",\"coordinates\":[-105.01621,39.57422]}}]}";
 
-        this.validateInput(this.sut::parseGeoJson, shapeJson, "unknown geo_shape [InvalidShape]");
+        this.validateInput(this.sut::parseGeoJson, shapeJson, "must be a valid FeatureCollection");
     }
 
     @Test
     public void should_parseValidPoint() {
-        String shapeJson = "{\"type\":\"Point\",\"coordinates\":[-105.01621,39.57422]}";
+        String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[-105.01621,39.57422]}}]}";
 
         this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY);
     }
 
     @Test
     public void should_parseValidMultiPoint() {
-        String shapeJson = "{\"type\":\"MultiPoint\",\"coordinates\":[[-105.01621,39.57422],[-80.666513,35.053994]]}";
+        String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"MultiPoint\",\"coordinates\":[[-105.01621,39.57422],[-80.666513,35.053994]]}}]}";
 
         this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY);
     }
 
     @Test
     public void should_parseValidLineString() {
-        String shapeJson = "{\"type\":\"LineString\",\"coordinates\":[[-101.744384,39.32155],[-101.552124,39.330048],[-101.403808,39.330048],[-101.332397,39.364032],[-101.041259,39.368279],[-100.975341,39.304549],[-100.914916,39.245016],[-100.843505,39.164141],[-100.805053,39.104488],[-100.491943,39.100226],[-100.437011,39.095962],[-100.338134,39.095962],[-100.195312,39.027718],[-100.008544,39.010647],[-99.865722,39.00211],[-99.684448,38.972221],[-99.51416,38.929502],[-99.382324,38.920955],[-99.321899,38.895308],[-99.113159,38.869651],[-99.0802,38.85682],[-98.822021,38.85682],[-98.448486,38.848264],[-98.206787,38.848264],[-98.020019,38.878204],[-97.635498,38.873928]]}";
+        String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-101.744384,39.32155],[-101.552124,39.330048],[-101.403808,39.330048],[-101.332397,39.364032],[-101.041259,39.368279],[-100.975341,39.304549],[-100.914916,39.245016],[-100.843505,39.164141],[-100.805053,39.104488],[-100.491943,39.100226],[-100.437011,39.095962],[-100.338134,39.095962],[-100.195312,39.027718],[-100.008544,39.010647],[-99.865722,39.00211],[-99.684448,38.972221],[-99.51416,38.929502],[-99.382324,38.920955],[-99.321899,38.895308],[-99.113159,38.869651],[-99.0802,38.85682],[-98.822021,38.85682],[-98.448486,38.848264],[-98.206787,38.848264],[-98.020019,38.878204],[-97.635498,38.873928]]}}]}";
 
         this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY);
     }
 
     @Test
     public void should_parseValidMultiLineString() {
-        String shapeJson = "{\"type\":\"MultiLineString\",\"coordinates\":[[[-105.021443,39.578057],[-105.021507,39.577809],[-105.021572,39.577495],[-105.021572,39.577164],[-105.021572,39.577032],[-105.021529,39.576784]],[[-105.019898,39.574997],[-105.019598,39.574898],[-105.019061,39.574782]],[[-105.017173,39.574402],[-105.01698,39.574385],[-105.016636,39.574385],[-105.016508,39.574402],[-105.01595,39.57427]],[[-105.014276,39.573972],[-105.014126,39.574038],[-105.013825,39.57417],[-105.01331,39.574452]]]}";
+        String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"MultiLineString\",\"coordinates\":[[[-105.021443,39.578057],[-105.021507,39.577809],[-105.021572,39.577495],[-105.021572,39.577164],[-105.021572,39.577032],[-105.021529,39.576784]],[[-105.019898,39.574997],[-105.019598,39.574898],[-105.019061,39.574782]],[[-105.017173,39.574402],[-105.01698,39.574385],[-105.016636,39.574385],[-105.016508,39.574402],[-105.01595,39.57427]],[[-105.014276,39.573972],[-105.014126,39.574038],[-105.013825,39.57417],[-105.01331,39.574452]]]}}]}";
 
         this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY);
     }
 
     @Test
     public void should_parseValidPolygon() {
-        String shapeJson = "{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[101,0],[101,1],[100,1],[100,0]]]}";
+        String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[100,0],[101,0],[101,1],[100,1],[100,0]]]}}]}";
 
         this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY);
     }
 
     @Test
     public void should_throwException_parseInvalidPolygon_malformedLatitude() {
-        String shapeJson = "{\"type\":\"Polygon\",\"coordinates\":[[[100,\"afgg\"],[101,0],[101,1],[100,1],[100,0]]]}";
+        String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[100,\"afgg\"],[101,0],[101,1],[100,1],[100,0]]]}}]}";
 
-        this.validateInput(this.sut::parseGeoJson, shapeJson, "geo coordinates must be numbers");
+        this.validateInput(this.sut::parseGeoJson, shapeJson, "unable to parse FeatureCollection");
     }
 
     @Test
     public void should_parseValidMultiPolygon() {
-        String shapeJson = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[107,7],[108,7],[108,8],[107,8],[107,7]]],[[[100,0],[101,0],[101,1],[100,1],[100,0]]]]}";
+        String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"MultiPolygon\",\"coordinates\":[[[[107,7],[108,7],[108,8],[107,8],[107,7]]],[[[100,0],[101,0],[101,1],[100,1],[100,0]]]]}}]}";
 
         this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY);
     }
 
     @Test
     public void should_parseValidGeometryCollection() {
-        String shapeJson = "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[-80.660805,35.049392]},{\"type\":\"Polygon\",\"coordinates\":[[[-80.664582,35.044965],[-80.663874,35.04428],[-80.662586,35.04558],[-80.663444,35.046036],[-80.664582,35.044965]]]},{\"type\":\"LineString\",\"coordinates\":[[-80.662372,35.059509],[-80.662693,35.059263],[-80.662844,35.05893],[-80.66308,35.058332],[-80.663595,35.057753],[-80.663874,35.057401],[-80.66441,35.057033],[-80.664861,35.056787],[-80.665419,35.056506],[-80.665633,35.056312],[-80.666019,35.055891],[-80.666191,35.055452],[-80.666191,35.055171],[-80.666255,35.05489],[-80.666213,35.054222],[-80.666213,35.053924],[-80.665955,35.052905],[-80.665698,35.052044],[-80.665504,35.051482],[-80.665762,35.050481],[-80.66617,35.049725],[-80.666513,35.049286],[-80.666921,35.048531],[-80.667006,35.048215],[-80.667071,35.047775],[-80.667049,35.047389],[-80.666964,35.046985],[-80.666813,35.046353],[-80.666599,35.045966],[-80.666406,35.045615],[-80.665998,35.045193],[-80.665526,35.044877],[-80.664989,35.044543],[-80.664496,35.044174],[-80.663852,35.043876],[-80.663037,35.043717]]}]}";
+        String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[-80.660805,35.049392]},{\"type\":\"Polygon\",\"coordinates\":[[[-80.664582,35.044965],[-80.663874,35.04428],[-80.662586,35.04558],[-80.663444,35.046036],[-80.664582,35.044965]]]},{\"type\":\"LineString\",\"coordinates\":[[-80.662372,35.059509],[-80.662693,35.059263],[-80.662844,35.05893],[-80.66308,35.058332],[-80.663595,35.057753],[-80.663874,35.057401],[-80.66441,35.057033],[-80.664861,35.056787],[-80.665419,35.056506],[-80.665633,35.056312],[-80.666019,35.055891],[-80.666191,35.055452],[-80.666191,35.055171],[-80.666255,35.05489],[-80.666213,35.054222],[-80.666213,35.053924],[-80.665955,35.052905],[-80.665698,35.052044],[-80.665504,35.051482],[-80.665762,35.050481],[-80.66617,35.049725],[-80.666513,35.049286],[-80.666921,35.048531],[-80.667006,35.048215],[-80.667071,35.047775],[-80.667049,35.047389],[-80.666964,35.046985],[-80.666813,35.046353],[-80.666599,35.045966],[-80.666406,35.045615],[-80.665998,35.045193],[-80.665526,35.044877],[-80.664989,35.044543],[-80.664496,35.044174],[-80.663852,35.043876],[-80.663037,35.043717]]}]}}]}";
 
         this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY);
     }
 
     @Test
-    public void should_throwException_parseUnsupportedType_featureCollection() {
+    public void should_parseValidFeatureCollection() {
         String shapeJson = "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[1.9496737127045984,58.41415669686543],[1.8237672363511042,58.42946998193435],[1.8422735102001124,58.471472136376455],[1.9683241046247606,58.45614207250076],[1.9496737127045984,58.41415669686543]]]}}]}";
 
-        this.validateInput(this.sut::parseGeoJson, shapeJson, "unknown geo_shape [FeatureCollection]");
+        this.validateInput(this.sut::parseGeoJson, shapeJson, Strings.EMPTY);
     }
 
     @Test
     public void should_throwException_parseUnsupportedType_feature() {
         String shapeJson = "{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[-80.724878,35.265454],[-80.722646,35.260338],[-80.720329,35.260618],[-80.718698,35.260267],[-80.715093,35.260548],[-80.71681,35.255361],[-80.710887,35.255361],[-80.703248,35.265033],[-80.704793,35.268397],[-80.70857,35.268257],[-80.712518,35.270359],[-80.715179,35.267696],[-80.721359,35.267276],[-80.724878,35.265454]]]},\"properties\":{\"name\":\"Plaza Road Park\"}}";
 
-        this.validateInput(this.sut::parseGeoJson, shapeJson, "unknown geo_shape [Feature]");
+        this.validateInput(this.sut::parseGeoJson, shapeJson, "must be a valid FeatureCollection");
     }
 
-    private void validateInput(Function<Map<String, Object>, String> parser, String shapeJson, String errorMessage) {
+    private void validateInput(Function<Map<String, Object>, Map<String, Object>> parser, String shapeJson, String errorMessage) {
         try {
             Type type = new TypeToken<Map<String, Object>>() {}.getType();
             Map<String, Object> shapeObj = new Gson().fromJson(shapeJson, type);
 
-            String parsedShape = parser.apply(shapeObj);
+            Map<String, Object> parsedShape = parser.apply(shapeObj);
             assertNotNull(parsedShape);
+            assertTrue(Strings.isNullOrEmpty(errorMessage));
         } catch (IllegalArgumentException e) {
-            assertThat(String.format("Incorrect error message for geo-json parsing [ %s ]", shapeJson),
-                    e.getMessage(), containsString(errorMessage));
+            if (Strings.isNullOrEmpty(errorMessage)) {
+                fail(String.format("error parsing valid geo-json %s", shapeJson));
+            } else {
+                assertThat(String.format("Incorrect error message for geo-json parsing [ %s ]", shapeJson),
+                        e.getMessage(), containsString(errorMessage));
+            }
         }
     }
 }
diff --git a/testing/indexer-test-core/src/main/resources/testData/index_records_3.json b/testing/indexer-test-core/src/main/resources/testData/index_records_3.json
index 983e7bdb9..58a7e0dee 100644
--- a/testing/indexer-test-core/src/main/resources/testData/index_records_3.json
+++ b/testing/indexer-test-core/src/main/resources/testData/index_records_3.json
@@ -4,10 +4,19 @@
     "data": {
       "WellName": "Data Platform Services - 51",
       "GeoShape": {
-        "type": "Point",
-        "coordinates": [
-          -105.01621,
-          39.57422
+        "type": "FeatureCollection",
+        "features": [
+          {
+            "type": "Feature",
+            "properties": {},
+            "geometry": {
+              "type": "Point",
+              "coordinates": [
+                -105.01621,
+                39.57422
+              ]
+            }
+          }
         ]
       }
     }
@@ -17,16 +26,25 @@
     "data": {
       "WellName": "Data Platform Services - 52",
       "GeoShape": {
-        "type": "MultiPoint",
-        "coordinates": [
-          [
-            -105.01621,
-            39.57422
-          ],
-          [
-            -80.666513,
-            35.053994
-          ]
+        "type": "FeatureCollection",
+        "features": [
+          {
+            "type": "Feature",
+            "properties": {},
+            "geometry": {
+              "type": "MultiPoint",
+              "coordinates": [
+                [
+                  -105.01621,
+                  39.57422
+                ],
+                [
+                  -80.666513,
+                  35.053994
+                ]
+              ]
+            }
+          }
         ]
       }
     }
@@ -36,112 +54,121 @@
     "data": {
       "WellName": "Data Platform Services - 53",
       "GeoShape": {
-        "type": "LineString",
-        "coordinates": [
-          [
-            -101.744384,
-            39.32155
-          ],
-          [
-            -101.552124,
-            39.330048
-          ],
-          [
-            -101.403808,
-            39.330048
-          ],
-          [
-            -101.332397,
-            39.364032
-          ],
-          [
-            -101.041259,
-            39.368279
-          ],
-          [
-            -100.975341,
-            39.304549
-          ],
-          [
-            -100.914916,
-            39.245016
-          ],
-          [
-            -100.843505,
-            39.164141
-          ],
-          [
-            -100.805053,
-            39.104488
-          ],
-          [
-            -100.491943,
-            39.100226
-          ],
-          [
-            -100.437011,
-            39.095962
-          ],
-          [
-            -100.338134,
-            39.095962
-          ],
-          [
-            -100.195312,
-            39.027718
-          ],
-          [
-            -100.008544,
-            39.010647
-          ],
-          [
-            -99.865722,
-            39.00211
-          ],
-          [
-            -99.684448,
-            38.972221
-          ],
-          [
-            -99.51416,
-            38.929502
-          ],
-          [
-            -99.382324,
-            38.920955
-          ],
-          [
-            -99.321899,
-            38.895308
-          ],
-          [
-            -99.113159,
-            38.869651
-          ],
-          [
-            -99.0802,
-            38.85682
-          ],
-          [
-            -98.822021,
-            38.85682
-          ],
-          [
-            -98.448486,
-            38.848264
-          ],
-          [
-            -98.206787,
-            38.848264
-          ],
-          [
-            -98.020019,
-            38.878204
-          ],
-          [
-            -97.635498,
-            38.873928
-          ]
+        "type": "FeatureCollection",
+        "features": [
+          {
+            "type": "Feature",
+            "properties": {},
+            "geometry": {
+              "type": "LineString",
+              "coordinates": [
+                [
+                  -101.744384,
+                  39.32155
+                ],
+                [
+                  -101.552124,
+                  39.330048
+                ],
+                [
+                  -101.403808,
+                  39.330048
+                ],
+                [
+                  -101.332397,
+                  39.364032
+                ],
+                [
+                  -101.041259,
+                  39.368279
+                ],
+                [
+                  -100.975341,
+                  39.304549
+                ],
+                [
+                  -100.914916,
+                  39.245016
+                ],
+                [
+                  -100.843505,
+                  39.164141
+                ],
+                [
+                  -100.805053,
+                  39.104488
+                ],
+                [
+                  -100.491943,
+                  39.100226
+                ],
+                [
+                  -100.437011,
+                  39.095962
+                ],
+                [
+                  -100.338134,
+                  39.095962
+                ],
+                [
+                  -100.195312,
+                  39.027718
+                ],
+                [
+                  -100.008544,
+                  39.010647
+                ],
+                [
+                  -99.865722,
+                  39.00211
+                ],
+                [
+                  -99.684448,
+                  38.972221
+                ],
+                [
+                  -99.51416,
+                  38.929502
+                ],
+                [
+                  -99.382324,
+                  38.920955
+                ],
+                [
+                  -99.321899,
+                  38.895308
+                ],
+                [
+                  -99.113159,
+                  38.869651
+                ],
+                [
+                  -99.0802,
+                  38.85682
+                ],
+                [
+                  -98.822021,
+                  38.85682
+                ],
+                [
+                  -98.448486,
+                  38.848264
+                ],
+                [
+                  -98.206787,
+                  38.848264
+                ],
+                [
+                  -98.020019,
+                  38.878204
+                ],
+                [
+                  -97.635498,
+                  38.873928
+                ]
+              ]
+            }
+          }
         ]
       }
     }
@@ -151,88 +178,97 @@
     "data": {
       "WellName": "Data Platform Services - 54",
       "GeoShape": {
-        "type": "MultiLineString",
-        "coordinates": [
-          [
-            [
-              -105.021443,
-              39.578057
-            ],
-            [
-              -105.021507,
-              39.577809
-            ],
-            [
-              -105.021572,
-              39.577495
-            ],
-            [
-              -105.021572,
-              39.577164
-            ],
-            [
-              -105.021572,
-              39.577032
-            ],
-            [
-              -105.021529,
-              39.576784
-            ]
-          ],
-          [
-            [
-              -105.019898,
-              39.574997
-            ],
-            [
-              -105.019598,
-              39.574898
-            ],
-            [
-              -105.019061,
-              39.574782
-            ]
-          ],
-          [
-            [
-              -105.017173,
-              39.574402
-            ],
-            [
-              -105.01698,
-              39.574385
-            ],
-            [
-              -105.016636,
-              39.574385
-            ],
-            [
-              -105.016508,
-              39.574402
-            ],
-            [
-              -105.01595,
-              39.57427
-            ]
-          ],
-          [
-            [
-              -105.014276,
-              39.573972
-            ],
-            [
-              -105.014126,
-              39.574038
-            ],
-            [
-              -105.013825,
-              39.57417
-            ],
-            [
-              -105.01331,
-              39.574452
-            ]
-          ]
+        "type": "FeatureCollection",
+        "features": [
+          {
+            "type": "Feature",
+            "properties": {},
+            "geometry": {
+              "type": "MultiLineString",
+              "coordinates": [
+                [
+                  [
+                    -105.021443,
+                    39.578057
+                  ],
+                  [
+                    -105.021507,
+                    39.577809
+                  ],
+                  [
+                    -105.021572,
+                    39.577495
+                  ],
+                  [
+                    -105.021572,
+                    39.577164
+                  ],
+                  [
+                    -105.021572,
+                    39.577032
+                  ],
+                  [
+                    -105.021529,
+                    39.576784
+                  ]
+                ],
+                [
+                  [
+                    -105.019898,
+                    39.574997
+                  ],
+                  [
+                    -105.019598,
+                    39.574898
+                  ],
+                  [
+                    -105.019061,
+                    39.574782
+                  ]
+                ],
+                [
+                  [
+                    -105.017173,
+                    39.574402
+                  ],
+                  [
+                    -105.01698,
+                    39.574385
+                  ],
+                  [
+                    -105.016636,
+                    39.574385
+                  ],
+                  [
+                    -105.016508,
+                    39.574402
+                  ],
+                  [
+                    -105.01595,
+                    39.57427
+                  ]
+                ],
+                [
+                  [
+                    -105.014276,
+                    39.573972
+                  ],
+                  [
+                    -105.014126,
+                    39.574038
+                  ],
+                  [
+                    -105.013825,
+                    39.57417
+                  ],
+                  [
+                    -105.01331,
+                    39.574452
+                  ]
+                ]
+              ]
+            }
+          }
         ]
       }
     }
@@ -242,30 +278,39 @@
     "data": {
       "WellName": "Data Platform Services - 55",
       "GeoShape": {
-        "type": "Polygon",
-        "coordinates": [
-          [
-            [
-              100,
-              0
-            ],
-            [
-              101,
-              0
-            ],
-            [
-              101,
-              1
-            ],
-            [
-              100,
-              1
-            ],
-            [
-              100,
-              0
-            ]
-          ]
+        "type": "FeatureCollection",
+        "features": [
+          {
+            "type": "Feature",
+            "properties": {},
+            "geometry": {
+              "type": "Polygon",
+              "coordinates": [
+                [
+                  [
+                    100,
+                    0
+                  ],
+                  [
+                    101,
+                    0
+                  ],
+                  [
+                    101,
+                    1
+                  ],
+                  [
+                    100,
+                    1
+                  ],
+                  [
+                    100,
+                    0
+                  ]
+                ]
+              ]
+            }
+          }
         ]
       }
     }
@@ -275,56 +320,65 @@
     "data": {
       "WellName": "Data Platform Services - 56",
       "GeoShape": {
-        "type": "MultiPolygon",
-        "coordinates": [
-          [
-            [
-              [
-                107,
-                7
-              ],
-              [
-                108,
-                7
-              ],
-              [
-                108,
-                8
-              ],
-              [
-                107,
-                8
-              ],
-              [
-                107,
-                7
-              ]
-            ]
-          ],
-          [
-            [
-              [
-                100,
-                0
-              ],
-              [
-                101,
-                0
-              ],
-              [
-                101,
-                1
-              ],
-              [
-                100,
-                1
-              ],
-              [
-                100,
-                0
+        "type": "FeatureCollection",
+        "features": [
+          {
+            "type": "Feature",
+            "properties": {},
+            "geometry": {
+              "type": "MultiPolygon",
+              "coordinates": [
+                [
+                  [
+                    [
+                      107,
+                      7
+                    ],
+                    [
+                      108,
+                      7
+                    ],
+                    [
+                      108,
+                      8
+                    ],
+                    [
+                      107,
+                      8
+                    ],
+                    [
+                      107,
+                      7
+                    ]
+                  ]
+                ],
+                [
+                  [
+                    [
+                      100,
+                      0
+                    ],
+                    [
+                      101,
+                      0
+                    ],
+                    [
+                      101,
+                      1
+                    ],
+                    [
+                      100,
+                      1
+                    ],
+                    [
+                      100,
+                      0
+                    ]
+                  ]
+                ]
               ]
-            ]
-          ]
+            }
+          }
         ]
       }
     }
@@ -334,190 +388,199 @@
     "data": {
       "WellName": "Data Platform Services - 57",
       "GeoShape": {
-        "type": "GeometryCollection",
-        "geometries": [
-          {
-            "type": "Point",
-            "coordinates": [
-              -80.660805,
-              35.049392
-            ]
-          },
-          {
-            "type": "Polygon",
-            "coordinates": [
-              [
-                [
-                  -80.664582,
-                  35.044965
-                ],
-                [
-                  -80.663874,
-                  35.04428
-                ],
-                [
-                  -80.662586,
-                  35.04558
-                ],
-                [
-                  -80.663444,
-                  35.046036
-                ],
-                [
-                  -80.664582,
-                  35.044965
-                ]
-              ]
-            ]
-          },
+        "type": "FeatureCollection",
+        "features": [
           {
-            "type": "LineString",
-            "coordinates": [
-              [
-                -80.662372,
-                35.059509
-              ],
-              [
-                -80.662693,
-                35.059263
-              ],
-              [
-                -80.662844,
-                35.05893
-              ],
-              [
-                -80.66308,
-                35.058332
-              ],
-              [
-                -80.663595,
-                35.057753
-              ],
-              [
-                -80.663874,
-                35.057401
-              ],
-              [
-                -80.66441,
-                35.057033
-              ],
-              [
-                -80.664861,
-                35.056787
-              ],
-              [
-                -80.665419,
-                35.056506
-              ],
-              [
-                -80.665633,
-                35.056312
-              ],
-              [
-                -80.666019,
-                35.055891
-              ],
-              [
-                -80.666191,
-                35.055452
-              ],
-              [
-                -80.666191,
-                35.055171
-              ],
-              [
-                -80.666255,
-                35.05489
-              ],
-              [
-                -80.666213,
-                35.054222
-              ],
-              [
-                -80.666213,
-                35.053924
-              ],
-              [
-                -80.665955,
-                35.052905
-              ],
-              [
-                -80.665698,
-                35.052044
-              ],
-              [
-                -80.665504,
-                35.051482
-              ],
-              [
-                -80.665762,
-                35.050481
-              ],
-              [
-                -80.66617,
-                35.049725
-              ],
-              [
-                -80.666513,
-                35.049286
-              ],
-              [
-                -80.666921,
-                35.048531
-              ],
-              [
-                -80.667006,
-                35.048215
-              ],
-              [
-                -80.667071,
-                35.047775
-              ],
-              [
-                -80.667049,
-                35.047389
-              ],
-              [
-                -80.666964,
-                35.046985
-              ],
-              [
-                -80.666813,
-                35.046353
-              ],
-              [
-                -80.666599,
-                35.045966
-              ],
-              [
-                -80.666406,
-                35.045615
-              ],
-              [
-                -80.665998,
-                35.045193
-              ],
-              [
-                -80.665526,
-                35.044877
-              ],
-              [
-                -80.664989,
-                35.044543
-              ],
-              [
-                -80.664496,
-                35.044174
-              ],
-              [
-                -80.663852,
-                35.043876
-              ],
-              [
-                -80.663037,
-                35.043717
+            "type": "Feature",
+            "properties": {},
+            "geometry": {
+              "type": "GeometryCollection",
+              "geometries": [
+                {
+                  "type": "Point",
+                  "coordinates": [
+                    -80.660805,
+                    35.049392
+                  ]
+                },
+                {
+                  "type": "Polygon",
+                  "coordinates": [
+                    [
+                      [
+                        -80.664582,
+                        35.044965
+                      ],
+                      [
+                        -80.663874,
+                        35.04428
+                      ],
+                      [
+                        -80.662586,
+                        35.04558
+                      ],
+                      [
+                        -80.663444,
+                        35.046036
+                      ],
+                      [
+                        -80.664582,
+                        35.044965
+                      ]
+                    ]
+                  ]
+                },
+                {
+                  "type": "LineString",
+                  "coordinates": [
+                    [
+                      -80.662372,
+                      35.059509
+                    ],
+                    [
+                      -80.662693,
+                      35.059263
+                    ],
+                    [
+                      -80.662844,
+                      35.05893
+                    ],
+                    [
+                      -80.66308,
+                      35.058332
+                    ],
+                    [
+                      -80.663595,
+                      35.057753
+                    ],
+                    [
+                      -80.663874,
+                      35.057401
+                    ],
+                    [
+                      -80.66441,
+                      35.057033
+                    ],
+                    [
+                      -80.664861,
+                      35.056787
+                    ],
+                    [
+                      -80.665419,
+                      35.056506
+                    ],
+                    [
+                      -80.665633,
+                      35.056312
+                    ],
+                    [
+                      -80.666019,
+                      35.055891
+                    ],
+                    [
+                      -80.666191,
+                      35.055452
+                    ],
+                    [
+                      -80.666191,
+                      35.055171
+                    ],
+                    [
+                      -80.666255,
+                      35.05489
+                    ],
+                    [
+                      -80.666213,
+                      35.054222
+                    ],
+                    [
+                      -80.666213,
+                      35.053924
+                    ],
+                    [
+                      -80.665955,
+                      35.052905
+                    ],
+                    [
+                      -80.665698,
+                      35.052044
+                    ],
+                    [
+                      -80.665504,
+                      35.051482
+                    ],
+                    [
+                      -80.665762,
+                      35.050481
+                    ],
+                    [
+                      -80.66617,
+                      35.049725
+                    ],
+                    [
+                      -80.666513,
+                      35.049286
+                    ],
+                    [
+                      -80.666921,
+                      35.048531
+                    ],
+                    [
+                      -80.667006,
+                      35.048215
+                    ],
+                    [
+                      -80.667071,
+                      35.047775
+                    ],
+                    [
+                      -80.667049,
+                      35.047389
+                    ],
+                    [
+                      -80.666964,
+                      35.046985
+                    ],
+                    [
+                      -80.666813,
+                      35.046353
+                    ],
+                    [
+                      -80.666599,
+                      35.045966
+                    ],
+                    [
+                      -80.666406,
+                      35.045615
+                    ],
+                    [
+                      -80.665998,
+                      35.045193
+                    ],
+                    [
+                      -80.665526,
+                      35.044877
+                    ],
+                    [
+                      -80.664989,
+                      35.044543
+                    ],
+                    [
+                      -80.664496,
+                      35.044174
+                    ],
+                    [
+                      -80.663852,
+                      35.043876
+                    ],
+                    [
+                      -80.663037,
+                      35.043717
+                    ]
+                  ]
+                }
               ]
-            ]
+            }
           }
         ]
       }
-- 
GitLab