From 2a8c1dbdf80c881067ce758a2d0c319c1e2f2d06 Mon Sep 17 00:00:00 2001 From: Peter-Josef Meisch Date: Mon, 5 Oct 2020 21:50:38 +0200 Subject: [PATCH] DATAES-930 - Add support for geo_shape type entity properties. Original PR: #531 --- .../elasticsearch-object-mapping.adoc | 42 +- .../core/convert/GeoConverters.java | 432 +++++++++++++++++- .../core/geo/CustomGeoModule.java | 2 + .../data/elasticsearch/core/geo/GeoJson.java | 43 ++ .../core/geo/GeoJsonGeometryCollection.java | 91 ++++ .../core/geo/GeoJsonLineString.java | 145 ++++++ .../core/geo/GeoJsonMultiLineString.java | 104 +++++ .../core/geo/GeoJsonMultiPoint.java | 145 ++++++ .../core/geo/GeoJsonMultiPolygon.java | 85 ++++ .../elasticsearch/core/geo/GeoJsonPoint.java | 120 +++++ .../core/geo/GeoJsonPolygon.java | 224 +++++++++ .../ElasticsearchPersistentProperty.java | 14 + .../SimpleElasticsearchPersistentEntity.java | 3 +- ...SimpleElasticsearchPersistentProperty.java | 11 +- .../ElasticsearchNamespaceHandlerTests.java | 3 + .../core/convert/GeoConvertersUnitTests.java | 400 ++++++++++++++++ ...appingElasticsearchConverterUnitTests.java | 304 ++++++++++++ .../elasticsearch/core/geo/GeoJsonEntity.java | 47 ++ .../GeoJsonGeometryCollectionUnitTests.java | 44 ++ .../core/geo/GeoJsonIntegrationTest.java | 102 +++++ .../core/geo/GeoJsonLineStringUnitTests.java | 83 ++++ .../geo/GeoJsonMultiLineStringUnitTests.java | 63 +++ .../core/geo/GeoJsonMultiPointUnitTests.java | 84 ++++ .../geo/GeoJsonMultiPolygonUnitTests.java | 47 ++ .../core/geo/GeoJsonPointUnitTests.java | 61 +++ .../core/geo/GeoJsonPolygonUnitTests.java | 95 ++++ .../geo/GeoJsonTransportIntegrationTest.java | 29 ++ ...lasticsearchRestTemplateConfiguration.java | 6 + 28 files changed, 2804 insertions(+), 25 deletions(-) create mode 100644 src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJson.java create mode 100644 src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonGeometryCollection.java create mode 100644 src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonLineString.java create mode 100644 src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiLineString.java create mode 100644 src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPoint.java create mode 100644 src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPolygon.java create mode 100644 src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPoint.java create mode 100644 src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPolygon.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/convert/GeoConvertersUnitTests.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonEntity.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonGeometryCollectionUnitTests.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonIntegrationTest.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonLineStringUnitTests.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiLineStringUnitTests.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPointUnitTests.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPolygonUnitTests.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPointUnitTests.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPolygonUnitTests.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonTransportIntegrationTest.java diff --git a/src/main/asciidoc/reference/elasticsearch-object-mapping.adoc b/src/main/asciidoc/reference/elasticsearch-object-mapping.adoc index de252e2c7..f2cb62ce4 100644 --- a/src/main/asciidoc/reference/elasticsearch-object-mapping.adoc +++ b/src/main/asciidoc/reference/elasticsearch-object-mapping.adoc @@ -44,8 +44,8 @@ The following annotations are available: ** `name`: The name of the field as it will be represented in the Elasticsearch document, if not set, the Java field name is used. ** `type`: the field type, can be one of _Text, Keyword, Long, Integer, Short, Byte, Double, Float, Half_Float, Scaled_Float, Date, Date_Nanos, Boolean, Binary, Integer_Range, Float_Range, Long_Range, Double_Range, Date_Range, Ip_Range, Object, Nested, Ip, TokenCount, Percolator, Flattened, Search_As_You_Type_. See https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html[Elasticsearch Mapping Types] ** `format` and `pattern` definitions for the _Date_ type. `format` must be defined for date types. -** `store`: Flag wether the original field value should be store in Elasticsearch, default value is _false_. -** `analyzer`, `searchAnalyzer`, `normalizer` for specifying custom custom analyzers and normalizer. +** `store`: Flag whether the original field value should be store in Elasticsearch, default value is _false_. +** `analyzer`, `searchAnalyzer`, `normalizer` for specifying custom analyzers and normalizer. * `@GeoPoint`: marks a field as _geo_point_ datatype. Can be omitted if the field is an instance of the `GeoPoint` class. NOTE: Properties that derive from `TemporalAccessor` must either have a `@Field` annotation of type `FieldType.Date` or a custom converter must be registered for this type. + @@ -136,6 +136,44 @@ public class Address { ---- ==== +==== GeoJson Types + +Spring Data Elasticsearch supports the GeoJson types by providing an interface `GeoJson` and implementations for the different geometries. They are mapped to Elasticsearch +documents according to the GeoJson specification. The corresponding properties of the entity are specified as `geo_shape` when the index mappings is written. + +.GeoJson types +==== +[source,java] +---- +public class Address { + + String city, street; + GeoJsonPoint location; +} +---- +[source,json] +---- +{ + "city": "Los Angeles", + "street": "2800 East Observatory Road", + "location": { + "type": "Point", + "coordinates": [-118.3026284, 34.118347] + } +} +---- +==== + +The following GeoJson types are implemented: + +* `GeoJsonPoint` +* `GeoJsonMultiPoint` +* `GeoJsonLineString` +* `GeoJsonMultiLineString` +* `GeoJsonPolygon` +* `GeoJsonMultiPolygon` +* `GeoJsonGeometryCollection` + ==== Collections For values inside Collections apply the same mapping rules as for aggregate roots when it comes to _type hints_ and <>. diff --git a/src/main/java/org/springframework/data/elasticsearch/core/convert/GeoConverters.java b/src/main/java/org/springframework/data/elasticsearch/core/convert/GeoConverters.java index 02dec2f0b..1d7c8c255 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/convert/GeoConverters.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/convert/GeoConverters.java @@ -18,13 +18,25 @@ package org.springframework.data.elasticsearch.core.convert; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; import org.springframework.core.convert.converter.Converter; import org.springframework.data.convert.ReadingConverter; import org.springframework.data.convert.WritingConverter; +import org.springframework.data.elasticsearch.core.geo.GeoJson; +import org.springframework.data.elasticsearch.core.geo.GeoJsonGeometryCollection; +import org.springframework.data.elasticsearch.core.geo.GeoJsonLineString; +import org.springframework.data.elasticsearch.core.geo.GeoJsonMultiLineString; +import org.springframework.data.elasticsearch.core.geo.GeoJsonMultiPoint; +import org.springframework.data.elasticsearch.core.geo.GeoJsonMultiPolygon; +import org.springframework.data.elasticsearch.core.geo.GeoJsonPoint; +import org.springframework.data.elasticsearch.core.geo.GeoJsonPolygon; import org.springframework.data.elasticsearch.core.geo.GeoPoint; import org.springframework.data.geo.Point; +import org.springframework.util.Assert; import org.springframework.util.NumberUtils; /** @@ -38,10 +50,19 @@ class GeoConverters { static Collection> getConvertersToRegister() { - return Arrays.asList(PointToMapConverter.INSTANCE, MapToPointConverter.INSTANCE, GeoPointToMapConverter.INSTANCE, - MapToGeoPointConverter.INSTANCE); + return Arrays.asList(PointToMapConverter.INSTANCE, MapToPointConverter.INSTANCE, // + GeoPointToMapConverter.INSTANCE, MapToGeoPointConverter.INSTANCE, // + GeoJsonToMapConverter.INSTANCE, MapToGeoJsonConverter.INSTANCE, // + GeoJsonPointToMapConverter.INSTANCE, MapToGeoJsonPointConverter.INSTANCE, // + GeoJsonMultiPointToMapConverter.INSTANCE, MapToGeoJsonMultiPointConverter.INSTANCE, // + GeoJsonLineStringToMapConverter.INSTANCE, MapToGeoJsonLineStringConverter.INSTANCE, // + GeoJsonMultiLineStringToMapConverter.INSTANCE, MapToGeoJsonMultiLineStringConverter.INSTANCE, // + GeoJsonPolygonToMapConverter.INSTANCE, MapToGeoJsonPolygonConverter.INSTANCE, // + GeoJsonMultiPolygonToMapConverter.INSTANCE, MapToGeoJsonMultiPolygonConverter.INSTANCE, // + GeoJsonGeometryCollectionToMapConverter.INSTANCE, MapToGeoJsonGeometryCollectionConverter.INSTANCE); } + // region Point /** * {@link Converter} to write a {@link Point} to {@link Map} using {@code lat/long} properties. */ @@ -60,23 +81,6 @@ class GeoConverters { } } - /** - * {@link Converter} to write a {@link GeoPoint} to {@link Map} using {@code lat/long} properties. - */ - @WritingConverter - enum GeoPointToMapConverter implements Converter> { - - INSTANCE; - - @Override - public Map convert(GeoPoint source) { - Map target = new LinkedHashMap<>(); - target.put("lat", source.getLat()); - target.put("lon", source.getLon()); - return target; - } - } - /** * {@link Converter} to read a {@link Point} from {@link Map} using {@code lat/long} properties. */ @@ -93,10 +97,27 @@ class GeoConverters { return new Point(x, y); } } + // endregion + // region GeoPoint /** - * {@link Converter} to read a {@link GeoPoint} from {@link Map} using {@code lat/long} properties. + * {@link Converter} to write a {@link GeoPoint} to {@link Map} using {@code lat/long} properties. */ + @WritingConverter + enum GeoPointToMapConverter implements Converter> { + + INSTANCE; + + @Override + public Map convert(GeoPoint source) { + Map target = new LinkedHashMap<>(); + target.put("lat", source.getLat()); + target.put("lon", source.getLon()); + return target; + } + + } + @ReadingConverter enum MapToGeoPointConverter implements Converter, GeoPoint> { @@ -110,4 +131,375 @@ class GeoConverters { return new GeoPoint(lat, lon); } } + // endregion + + // region GeoJson + @WritingConverter + enum GeoJsonToMapConverter implements Converter>, Map> { + + INSTANCE; + + @Override + public Map convert(GeoJson> source) { + if (source instanceof GeoJsonPoint) { + return GeoJsonPointToMapConverter.INSTANCE.convert((GeoJsonPoint) source); + } else if (source instanceof GeoJsonMultiPoint) { + return GeoJsonMultiPointToMapConverter.INSTANCE.convert((GeoJsonMultiPoint) source); + } else if (source instanceof GeoJsonLineString) { + return GeoJsonLineStringToMapConverter.INSTANCE.convert((GeoJsonLineString) source); + } else if (source instanceof GeoJsonMultiLineString) { + return GeoJsonMultiLineStringToMapConverter.INSTANCE.convert((GeoJsonMultiLineString) source); + } else if (source instanceof GeoJsonPolygon) { + return GeoJsonPolygonToMapConverter.INSTANCE.convert((GeoJsonPolygon) source); + } else if (source instanceof GeoJsonMultiPolygon) { + return GeoJsonMultiPolygonToMapConverter.INSTANCE.convert((GeoJsonMultiPolygon) source); + } else if (source instanceof GeoJsonGeometryCollection) { + return GeoJsonGeometryCollectionToMapConverter.INSTANCE.convert((GeoJsonGeometryCollection) source); + } else { + throw new IllegalArgumentException("unknown GeoJson class " + source.getClass().getSimpleName()); + } + } + } + + @ReadingConverter + enum MapToGeoJsonConverter implements Converter, GeoJson>> { + + INSTANCE; + + @Override + public GeoJson> convert(Map source) { + + String type = GeoConverters.getGeoJsonType(source); + + switch (type) { + case GeoJsonPoint.TYPE: + return MapToGeoJsonPointConverter.INSTANCE.convert(source); + case GeoJsonMultiPoint.TYPE: + return MapToGeoJsonMultiPointConverter.INSTANCE.convert(source); + case GeoJsonLineString.TYPE: + return MapToGeoJsonLineStringConverter.INSTANCE.convert(source); + case GeoJsonMultiLineString.TYPE: + return MapToGeoJsonMultiLineStringConverter.INSTANCE.convert(source); + case GeoJsonPolygon.TYPE: + return MapToGeoJsonPolygonConverter.INSTANCE.convert(source); + case GeoJsonMultiPolygon.TYPE: + return MapToGeoJsonMultiPolygonConverter.INSTANCE.convert(source); + case GeoJsonGeometryCollection.TYPE: + return MapToGeoJsonGeometryCollectionConverter.INSTANCE.convert(source); + default: + throw new IllegalArgumentException("unknown GeoJson type " + type); + } + } + } + // endregion + + // region GeoJsonPoint + @WritingConverter + enum GeoJsonPointToMapConverter implements Converter> { + + INSTANCE; + + @Override + public Map convert(GeoJsonPoint geoJsonPoint) { + Map map = new LinkedHashMap<>(); + map.put("type", geoJsonPoint.getType()); + map.put("coordinates", geoJsonPoint.getCoordinates()); + return map; + } + } + + @ReadingConverter + enum MapToGeoJsonPointConverter implements Converter, GeoJsonPoint> { + + INSTANCE; + + @Override + public GeoJsonPoint convert(Map source) { + + String type = GeoConverters.getGeoJsonType(source); + Assert.isTrue(type.equals(GeoJsonPoint.TYPE), "does not contain a type 'Point'"); + + Object coordinates = source.get("coordinates"); + Assert.notNull(coordinates, "Document to convert does not contain coordinates"); + Assert.isTrue(coordinates instanceof List, "coordinates must be a List of Numbers"); + // noinspection unchecked + List numbers = (List) coordinates; + Assert.isTrue(numbers.size() >= 2, "coordinates must have at least 2 elements"); + + return GeoJsonPoint.of(numbers.get(0).doubleValue(), numbers.get(1).doubleValue()); + } + } + // endregion + + // region GeoJsonMultiPoint + @WritingConverter + enum GeoJsonMultiPointToMapConverter implements Converter> { + + INSTANCE; + + @Override + public Map convert(GeoJsonMultiPoint geoJsonMultiPoint) { + Map map = new LinkedHashMap<>(); + map.put("type", geoJsonMultiPoint.getType()); + map.put("coordinates", pointsToCoordinates(geoJsonMultiPoint.getCoordinates())); + return map; + } + } + + @ReadingConverter + enum MapToGeoJsonMultiPointConverter implements Converter, GeoJsonMultiPoint> { + + INSTANCE; + + @Override + public GeoJsonMultiPoint convert(Map source) { + + String type = GeoConverters.getGeoJsonType(source); + Assert.isTrue(type.equals(GeoJsonMultiPoint.TYPE), "does not contain a type 'MultiPoint'"); + Object coordinates = source.get("coordinates"); + Assert.notNull(coordinates, "Document to convert does not contain coordinates"); + Assert.isTrue(coordinates instanceof List, "coordinates must be a List"); + + // noinspection unchecked + return GeoJsonMultiPoint.of(coordinatesToPoints((List>) coordinates)); + } + } + // endregion + + // region GeoJsonLineString + @WritingConverter + enum GeoJsonLineStringToMapConverter implements Converter> { + + INSTANCE; + + @Override + public Map convert(GeoJsonLineString geoJsonLineString) { + Map map = new LinkedHashMap<>(); + map.put("type", geoJsonLineString.getType()); + map.put("coordinates", pointsToCoordinates(geoJsonLineString.getCoordinates())); + return map; + } + } + + @ReadingConverter + enum MapToGeoJsonLineStringConverter implements Converter, GeoJsonLineString> { + + INSTANCE; + + @Override + public GeoJsonLineString convert(Map source) { + + String type = GeoConverters.getGeoJsonType(source); + Assert.isTrue(type.equals(GeoJsonLineString.TYPE), "does not contain a type 'LineString'"); + Object coordinates = source.get("coordinates"); + Assert.notNull(coordinates, "Document to convert does not contain coordinates"); + Assert.isTrue(coordinates instanceof List, "coordinates must be a List"); + + // noinspection unchecked + return GeoJsonLineString.of(coordinatesToPoints((List>) coordinates)); + } + } + // endregion + + // region GeoJsonMultiLineString + @WritingConverter + enum GeoJsonMultiLineStringToMapConverter implements Converter> { + + INSTANCE; + + @Override + public Map convert(GeoJsonMultiLineString source) { + return geoJsonLinesStringsToMap(source.getType(), source.getCoordinates()); + } + } + + @ReadingConverter + enum MapToGeoJsonMultiLineStringConverter implements Converter, GeoJsonMultiLineString> { + + INSTANCE; + + @Override + public GeoJsonMultiLineString convert(Map source) { + + String type = GeoConverters.getGeoJsonType(source); + Assert.isTrue(type.equals(GeoJsonMultiLineString.TYPE), "does not contain a type 'MultiLineString'"); + List lines = geoJsonLineStringsFromMap(source); + return GeoJsonMultiLineString.of(lines); + } + } + // endregion + + // region GeoJsonPolygon + @WritingConverter + enum GeoJsonPolygonToMapConverter implements Converter> { + + INSTANCE; + + @Override + public Map convert(GeoJsonPolygon source) { + return geoJsonLinesStringsToMap(source.getType(), source.getCoordinates()); + } + } + + @ReadingConverter + enum MapToGeoJsonPolygonConverter implements Converter, GeoJsonPolygon> { + + INSTANCE; + + @Override + public GeoJsonPolygon convert(Map source) { + + String type = GeoConverters.getGeoJsonType(source); + Assert.isTrue(type.equals(GeoJsonPolygon.TYPE), "does not contain a type 'Polygon'"); + List lines = geoJsonLineStringsFromMap(source); + Assert.isTrue(lines.size() > 0, "no linestrings defined in polygon"); + GeoJsonPolygon geoJsonPolygon = GeoJsonPolygon.of(lines.get(0)); + for (int i = 1; i < lines.size(); i++) { + geoJsonPolygon = geoJsonPolygon.withInnerRing(lines.get(i)); + } + return geoJsonPolygon; + } + } + // endregion + + // region GeoJsonMultiPolygon + @WritingConverter + enum GeoJsonMultiPolygonToMapConverter implements Converter> { + + INSTANCE; + + @Override + public Map convert(GeoJsonMultiPolygon source) { + + Map map = new LinkedHashMap<>(); + map.put("type", source.getType()); + + List coordinates = source.getCoordinates().stream() // + .map(GeoJsonPolygonToMapConverter.INSTANCE::convert) // + .filter(Objects::nonNull) // + .map(it -> it.get("coordinates")) // + .collect(Collectors.toList()); // + map.put("coordinates", coordinates); + + return map; + } + } + + @ReadingConverter + enum MapToGeoJsonMultiPolygonConverter implements Converter, GeoJsonMultiPolygon> { + + INSTANCE; + + @Override + public GeoJsonMultiPolygon convert(Map source) { + + String type = GeoConverters.getGeoJsonType(source); + Assert.isTrue(type.equals(GeoJsonMultiPolygon.TYPE), "does not contain a type 'MultiPolygon'"); + Object coordinates = source.get("coordinates"); + Assert.notNull(coordinates, "Document to convert does not contain coordinates"); + Assert.isTrue(coordinates instanceof List, "coordinates must be a List"); + + List geoJsonPolygons = ((List) coordinates).stream().map(it -> { + Map map = new LinkedHashMap<>(); + map.put("type", GeoJsonPolygon.TYPE); + map.put("coordinates", it); + return map; + }).map(MapToGeoJsonPolygonConverter.INSTANCE::convert).collect(Collectors.toList()); + + return GeoJsonMultiPolygon.of(geoJsonPolygons); + } + } + // endregion + + // region GeoJsonGeometryCollection + @WritingConverter + enum GeoJsonGeometryCollectionToMapConverter implements Converter> { + + INSTANCE; + + @Override + public Map convert(GeoJsonGeometryCollection source) { + + Map map = new LinkedHashMap<>(); + map.put("type", source.getType()); + List> geometries = source.getGeometries().stream() + .map(GeoJsonToMapConverter.INSTANCE::convert).collect(Collectors.toList()); + map.put("geometries", geometries); + + return map; + } + } + + @ReadingConverter + enum MapToGeoJsonGeometryCollectionConverter implements Converter, GeoJsonGeometryCollection> { + + INSTANCE; + + @Override + public GeoJsonGeometryCollection convert(Map source) { + + String type = GeoConverters.getGeoJsonType(source); + Assert.isTrue(type.equals(GeoJsonGeometryCollection.TYPE), "does not contain a type 'GeometryCollection'"); + Object geometries = source.get("geometries"); + Assert.notNull(geometries, "Document to convert does not contain geometries"); + Assert.isTrue(geometries instanceof List, "geometries must be a List"); + + // noinspection unchecked + List> geoJsonList = ((List>) geometries).stream() + .map(MapToGeoJsonConverter.INSTANCE::convert).collect(Collectors.toList()); + return GeoJsonGeometryCollection.of(geoJsonList); + } + } + // endregion + + // region helper functions + private static String getGeoJsonType(Map source) { + + Object type = source.get("type"); + Assert.notNull(type, "Document to convert does not contain a type"); + Assert.isTrue(type instanceof String, "type must be a String"); + + return type.toString(); + } + + private static List toCoordinates(Point point) { + return Arrays.asList(point.getX(), point.getY()); + } + + private static List> pointsToCoordinates(List points) { + return points.stream().map(GeoConverters::toCoordinates).collect(Collectors.toList()); + } + + private static List coordinatesToPoints(List> pointList) { + + Assert.isTrue(pointList.size() >= 2, "pointList must have at least 2 elements"); + + return pointList.stream().map(numbers -> { + Assert.isTrue(numbers.size() >= 2, "coordinates must have at least 2 elements"); + + return new Point(numbers.get(0).doubleValue(), numbers.get(1).doubleValue()); + }).collect(Collectors.toList()); + } + + private static Map geoJsonLinesStringsToMap(String type, List lineStrings) { + Map map = new LinkedHashMap<>(); + map.put("type", type); + List>> coordinates = lineStrings.stream() + .map(it -> GeoConverters.pointsToCoordinates(it.getCoordinates())).collect(Collectors.toList()); + map.put("coordinates", coordinates); + return map; + } + + private static List geoJsonLineStringsFromMap(Map source) { + Object coordinates = source.get("coordinates"); + Assert.notNull(coordinates, "Document to convert does not contain coordinates"); + Assert.isTrue(coordinates instanceof List, "coordinates must be a List"); + + // noinspection unchecked + List lines = ((List) coordinates).stream() + .map(it -> GeoJsonLineString.of(coordinatesToPoints((List>) it))).collect(Collectors.toList()); + return lines; + } + + // endregion } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/geo/CustomGeoModule.java b/src/main/java/org/springframework/data/elasticsearch/core/geo/CustomGeoModule.java index e13c97fe9..1db995f2c 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/geo/CustomGeoModule.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/geo/CustomGeoModule.java @@ -13,7 +13,9 @@ import org.springframework.data.geo.Point; /** * @author Artur Konaczak + * @deprecated since 4.1, not used anymore */ +@Deprecated public class CustomGeoModule extends SimpleModule { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJson.java b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJson.java new file mode 100644 index 000000000..6a65d86c9 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJson.java @@ -0,0 +1,43 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +/** + * Interface definition for structures defined in https://geojson.org/geojson-spec.html#geojson-objects + */ + String getType(); + + /** + * The value of the coordinates member is always an {@link Iterable}. The structure for the elements within is + * determined by {@link #getType()} of geometry. + * + * @return will never be {@literal null}. + * @see https://geojson.org/geojson-spec.html#geometry-objects + */ + T getCoordinates(); +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonGeometryCollection.java b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonGeometryCollection.java new file mode 100644 index 000000000..685c4391b --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonGeometryCollection.java @@ -0,0 +1,91 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.springframework.util.Assert; + +/** + * Defines a {@link GeoJsonGeometryCollection} that consists of a {@link List} of {@link GeoJson} objects.
+ * Copied from Spring Data Mongodb + * + * @author Christoph Strobl + * @author Peter-Josef Meisch + * @since 4.1 + * @see https://geojson.org/geojson-spec.html#geometry-collection + */ +public class GeoJsonGeometryCollection implements GeoJson>> { + + public static final String TYPE = "GeometryCollection"; + + private final List> geometries = new ArrayList<>(); + + private GeoJsonGeometryCollection(List> geometries) { + this.geometries.addAll(geometries); + } + + /** + * Creates a new {@link GeoJsonGeometryCollection} for the given {@link GeoJson} instances. + * + * @param geometries must not be {@literal null}. + */ + public static GeoJsonGeometryCollection of(List> geometries) { + + Assert.notNull(geometries, "Geometries must not be null!"); + + return new GeoJsonGeometryCollection(geometries); + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public Iterable> getCoordinates() { + return getGeometries(); + } + + public List> getGeometries() { + return Collections.unmodifiableList(this.geometries); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + GeoJsonGeometryCollection that = (GeoJsonGeometryCollection) o; + + return geometries.equals(that.geometries); + } + + @Override + public int hashCode() { + return geometries.hashCode(); + } + + @Override + public String toString() { + return "GeoJsonGeometryCollection{" + "geometries=" + geometries + '}'; + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonLineString.java b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonLineString.java new file mode 100644 index 000000000..d357b156d --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonLineString.java @@ -0,0 +1,145 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.data.geo.Point; +import org.springframework.util.Assert; + +/** + * {@link GeoJsonLineString} is defined as list of {@link Point}s.
+ * Copied from Spring Data Mongodb + * + * @author Christoph Strobl + * @author Peter-Josef Meisch + * @since 4.1 + * @see https://geojson.org/geojson-spec.html#multipoint + */ +public class GeoJsonLineString implements GeoJson> { + + public static final String TYPE = "LineString"; + + private final List points; + + private GeoJsonLineString(List points) { + this.points = new ArrayList<>(points); + } + + /** + * Creates a new {@link GeoJsonLineString} for the given {@link Point}s. + * + * @param points points must not be {@literal null} and have at least 2 entries. + */ + public static GeoJsonLineString of(List points) { + + Assert.notNull(points, "Points must not be null."); + Assert.isTrue(points.size() >= 2, "Minimum of 2 Points required."); + + return new GeoJsonLineString(points); + } + + /** + * Creates a new {@link GeoJsonLineString} for the given {@link Point}s. + * + * @param first must not be {@literal null}. + * @param second must not be {@literal null}. + * @param others must not be {@literal null}. + */ + public static GeoJsonLineString of(Point first, Point second, Point... others) { + + Assert.notNull(first, "First point must not be null!"); + Assert.notNull(second, "Second point must not be null!"); + Assert.notNull(others, "Additional points must not be null!"); + + List points = new ArrayList<>(); + points.add(first); + points.add(second); + points.addAll(Arrays.asList(others)); + + return new GeoJsonLineString(points); + } + + /** + * Creates a new {@link GeoJsonLineString} for the given {@link GeoPoint}s. + * + * @param geoPoints geoPoints must not be {@literal null} and have at least 2 entries. + */ + public static GeoJsonLineString ofGeoPoints(List geoPoints) { + + Assert.notNull(geoPoints, "Points must not be null."); + Assert.isTrue(geoPoints.size() >= 2, "Minimum of 2 Points required."); + + return new GeoJsonLineString(geoPoints.stream().map(GeoPoint::toPoint).collect(Collectors.toList())); + } + + /** + * Creates a new {@link GeoJsonLineString} for the given {@link GeoPoint}s. + * + * @param first must not be {@literal null}. + * @param second must not be {@literal null}. + * @param others must not be {@literal null}. + */ + public static GeoJsonLineString of(GeoPoint first, GeoPoint second, GeoPoint... others) { + + Assert.notNull(first, "First point must not be null!"); + Assert.notNull(second, "Second point must not be null!"); + Assert.notNull(others, "Additional points must not be null!"); + + List points = new ArrayList<>(); + points.add(GeoPoint.toPoint(first)); + points.add(GeoPoint.toPoint(second)); + points.addAll(Arrays.stream(others).map(GeoPoint::toPoint).collect(Collectors.toList())); + + return new GeoJsonLineString(points); + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public List getCoordinates() { + return Collections.unmodifiableList(this.points); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + GeoJsonLineString that = (GeoJsonLineString) o; + + return points.equals(that.points); + } + + @Override + public int hashCode() { + return points.hashCode(); + } + + @Override + public String toString() { + return "GeoJsonLineString{" + "points=" + points + '}'; + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiLineString.java b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiLineString.java new file mode 100644 index 000000000..d96764e74 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiLineString.java @@ -0,0 +1,104 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.data.geo.Point; +import org.springframework.util.Assert; + +/** + * {@link GeoJsonMultiLineString} is defined as list of {@link GeoJsonLineString}s.
+ * Copied from Spring Data Mongodb + * + * @author Christoph Strobl + * @author Peter-Josef Meisch + * @since 4.1 + * @see https://geojson.org/geojson-spec.html#multilinestring + */ +public class GeoJsonMultiLineString implements GeoJson> { + + public static final String TYPE = "MultiLineString"; + + private final List coordinates = new ArrayList<>(); + + private GeoJsonMultiLineString(List lines) { + this.coordinates.addAll(lines); + } + + /** + * Creates new {@link GeoJsonMultiLineString} for the given {@link GeoJsonLineString}s. + * + * @param lines must not be {@literal null}. + */ + public static GeoJsonMultiLineString of(List lines) { + + Assert.notNull(lines, "Lines for MultiLineString must not be null!"); + + return new GeoJsonMultiLineString(lines); + } + + /** + * Creates new {@link GeoJsonMultiLineString} for the given {@link Point}s. + * + * @param lines must not be {@literal null}. + */ + public static GeoJsonMultiLineString of(List... lines) { + + Assert.notEmpty(lines, "Points for MultiLineString must not be null!"); + List geoJsonLineStrings = Arrays.stream(lines).map(GeoJsonLineString::of) + .collect(Collectors.toList()); + + return new GeoJsonMultiLineString(geoJsonLineStrings); + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public List getCoordinates() { + return Collections.unmodifiableList(this.coordinates); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + GeoJsonMultiLineString that = (GeoJsonMultiLineString) o; + + return coordinates.equals(that.coordinates); + } + + @Override + public int hashCode() { + return coordinates.hashCode(); + } + + @Override + public String toString() { + return "GeoJsonMultiLineString{" + "coordinates=" + coordinates + '}'; + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPoint.java b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPoint.java new file mode 100644 index 000000000..0ca725b30 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPoint.java @@ -0,0 +1,145 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.data.geo.Point; +import org.springframework.util.Assert; + +/** + * {@link GeoJsonMultiPoint} is defined as list of {@link Point}s.
+ * Copied from Spring Data Mongodb + * + * @author Christoph Strobl + * @author Peter-Josef Meisch + * @since 4.1 + * @see https://geojson.org/geojson-spec.html#multipoint + */ +public class GeoJsonMultiPoint implements GeoJson> { + + public static final String TYPE = "MultiPoint"; + + private final List points; + + private GeoJsonMultiPoint(List points) { + this.points = new ArrayList<>(points); + } + + /** + * Creates a new {@link GeoJsonMultiPoint} for the given {@link Point}s. + * + * @param points points must not be {@literal null} and have at least 2 entries. + */ + public static GeoJsonMultiPoint of(List points) { + + Assert.notNull(points, "Points must not be null."); + Assert.isTrue(points.size() >= 2, "Minimum of 2 Points required."); + + return new GeoJsonMultiPoint(points); + } + + /** + * Creates a new {@link GeoJsonMultiPoint} for the given {@link Point}s. + * + * @param first must not be {@literal null}. + * @param second must not be {@literal null}. + * @param others must not be {@literal null}. + */ + public static GeoJsonMultiPoint of(Point first, Point second, Point... others) { + + Assert.notNull(first, "First point must not be null!"); + Assert.notNull(second, "Second point must not be null!"); + Assert.notNull(others, "Additional points must not be null!"); + + List points = new ArrayList<>(); + points.add(first); + points.add(second); + points.addAll(Arrays.asList(others)); + + return new GeoJsonMultiPoint(points); + } + + /** + * Creates a new {@link GeoJsonMultiPoint} for the given {@link GeoPoint}s. + * + * @param geoPoints geoPoints must not be {@literal null} and have at least 2 entries. + */ + public static GeoJsonMultiPoint ofGeoPoints(List geoPoints) { + + Assert.notNull(geoPoints, "Points must not be null."); + Assert.isTrue(geoPoints.size() >= 2, "Minimum of 2 Points required."); + + return new GeoJsonMultiPoint(geoPoints.stream().map(GeoPoint::toPoint).collect(Collectors.toList())); + } + + /** + * Creates a new {@link GeoJsonMultiPoint} for the given {@link GeoPoint}s. + * + * @param first must not be {@literal null}. + * @param second must not be {@literal null}. + * @param others must not be {@literal null}. + */ + public static GeoJsonMultiPoint of(GeoPoint first, GeoPoint second, GeoPoint... others) { + + Assert.notNull(first, "First point must not be null!"); + Assert.notNull(second, "Second point must not be null!"); + Assert.notNull(others, "Additional points must not be null!"); + + List points = new ArrayList<>(); + points.add(GeoPoint.toPoint(first)); + points.add(GeoPoint.toPoint(second)); + points.addAll(Arrays.stream(others).map(GeoPoint::toPoint).collect(Collectors.toList())); + + return new GeoJsonMultiPoint(points); + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public List getCoordinates() { + return Collections.unmodifiableList(this.points); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + GeoJsonMultiPoint that = (GeoJsonMultiPoint) o; + + return points.equals(that.points); + } + + @Override + public int hashCode() { + return points.hashCode(); + } + + @Override + public String toString() { + return "GeoJsonMultiPoint{" + "points=" + points + '}'; + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPolygon.java b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPolygon.java new file mode 100644 index 000000000..2890a38b0 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPolygon.java @@ -0,0 +1,85 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.springframework.util.Assert; + +/** + * {@link GeoJsonMultiPolygon} is defined as a list of {@link GeoJsonPolygon}s.
+ * Copied fro Spring Data Mongodb. + * + * @author Christoph Strobl + * @author Peter-Josef Meisch + * @since 4.1 + */ +public class GeoJsonMultiPolygon implements GeoJson> { + + public static final String TYPE = "MultiPolygon"; + + private List coordinates = new ArrayList(); + + private GeoJsonMultiPolygon(List polygons) { + this.coordinates.addAll(polygons); + } + + /** + * Creates a new {@link GeoJsonMultiPolygon} for the given {@link GeoJsonPolygon}s. + * + * @param polygons must not be {@literal null}. + */ + public static GeoJsonMultiPolygon of(List polygons) { + + Assert.notNull(polygons, "Polygons for MultiPolygon must not be null!"); + + return new GeoJsonMultiPolygon(polygons); + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public List getCoordinates() { + return Collections.unmodifiableList(this.coordinates); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + GeoJsonMultiPolygon that = (GeoJsonMultiPolygon) o; + + return coordinates.equals(that.coordinates); + } + + @Override + public int hashCode() { + return coordinates.hashCode(); + } + + @Override + public String toString() { + return "GeoJsonMultiPolygon{" + "coordinates=" + coordinates + '}'; + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPoint.java b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPoint.java new file mode 100644 index 000000000..348c37044 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPoint.java @@ -0,0 +1,120 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import java.util.Arrays; +import java.util.List; + +import org.springframework.data.geo.Point; + +/** + * {@link GeoJson} representation of {@link Point}.
+ * Copied from Spring Data Mongodb, not derived from {@link Point} as this conflicts with the already existing converter + * for Point in {@link org.springframework.data.elasticsearch.core.convert.GeoConverters}. + * + * @author Christoph Strobl + * @author Peter-Josef Meisch + * @since 4.1 + * @see https://geojson.org/geojson-spec.html#point + */ +public class GeoJsonPoint implements GeoJson> { + + private final double x; + private final double y; + + public static final String TYPE = "Point"; + + private GeoJsonPoint(double x, double y) { + this.x = x; + this.y = y; + } + + /** + * Creates {@link GeoJsonPoint} for given coordinates. + * + * @param x + * @param y + */ + public static GeoJsonPoint of(double x, double y) { + return new GeoJsonPoint(x, y); + } + + /** + * Creates {@link GeoJsonPoint} for given {@link Point}. + * + * @param point must not be {@literal null}. + */ + public static GeoJsonPoint of(Point point) { + return new GeoJsonPoint(point.getX(), point.getY()); + } + + /** + * Creates {@link GeoJsonPoint} for given {@link GeoPoint}. + * + * @param geoPoint must not be {@literal null}. + */ + public static GeoJsonPoint of(GeoPoint geoPoint) { + return new GeoJsonPoint(geoPoint.getLon(), geoPoint.getLat()); + } + + @Override + public String getType() { + return TYPE; + } + + public double getX() { + return x; + } + + public double getY() { + return y; + } + + @Override + public List getCoordinates() { + return Arrays.asList(getX(), getY()); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + GeoJsonPoint that = (GeoJsonPoint) o; + + if (Double.compare(that.x, x) != 0) + return false; + return Double.compare(that.y, y) == 0; + } + + @Override + public int hashCode() { + int result; + long temp; + temp = Double.doubleToLongBits(x); + result = (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(y); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public String toString() { + return "GeoJsonPoint{" + "x=" + x + ", y=" + y + '}'; + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPolygon.java b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPolygon.java new file mode 100644 index 000000000..643c94ef2 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPolygon.java @@ -0,0 +1,224 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.springframework.data.geo.Point; +import org.springframework.util.Assert; + +/** + * {@link GeoJson} representation of a polygon.
+ * Copied from Spring Data Mongodb + * + * @author Christoph Strobl + * @author Mark Paluch + * @author Peter-Josef Meisch + * @since 4.1 + * @see https://geojson.org/geojson-spec.html#polygon + */ +public class GeoJsonPolygon implements GeoJson> { + + public static final String TYPE = "Polygon"; + + private final List coordinates = new ArrayList<>(); + + private GeoJsonPolygon(GeoJsonLineString geoJsonLineString) { + Assert.notNull(geoJsonLineString, "geoJsonLineString must not be null"); + Assert.isTrue(geoJsonLineString.getCoordinates().size() >= 4, "geoJsonLineString must have at least 4 points"); + + this.coordinates.add(geoJsonLineString); + } + + private GeoJsonPolygon(List points) { + this(GeoJsonLineString.of(points)); + } + + /** + * Creates new {@link GeoJsonPolygon} from the given {@link GeoJsonLineString}. + * + * @param geoJsonLineString must not be {@literal null}. + */ + public static GeoJsonPolygon of(GeoJsonLineString geoJsonLineString) { + return new GeoJsonPolygon(geoJsonLineString); + } + + /** + * Creates new {@link GeoJsonPolygon} from the given {@link Point}s. + * + * @param points must not be {@literal null}. + */ + public static GeoJsonPolygon of(List points) { + return new GeoJsonPolygon(points); + } + + /** + * Creates new {@link GeoJsonPolygon} from the given {@link GeoPoint}s. + * + * @param geoPoints must not be {@literal null}. + */ + public static GeoJsonPolygon ofGeoPoints(List geoPoints) { + return new GeoJsonPolygon(GeoJsonLineString.ofGeoPoints(geoPoints)); + } + + /** + * Creates new {@link GeoJsonPolygon} from the given {@link Point}s. + * + * @param first must not be {@literal null}. + * @param second must not be {@literal null}. + * @param third must not be {@literal null}. + * @param fourth must not be {@literal null} + * @param others can be empty. + */ + public static GeoJsonPolygon of(Point first, Point second, Point third, Point fourth, Point... others) { + return new GeoJsonPolygon(asList(first, second, third, fourth, others)); + } + + /** + * Creates new {@link GeoJsonPolygon} from the given {@link GeoPoint}s. + * + * @param first must not be {@literal null}. + * @param second must not be {@literal null}. + * @param third must not be {@literal null}. + * @param fourth must not be {@literal null} + * @param others can be empty. + */ + public static GeoJsonPolygon of(GeoPoint first, GeoPoint second, GeoPoint third, GeoPoint fourth, + GeoPoint... others) { + return new GeoJsonPolygon(GeoJsonLineString.ofGeoPoints(asList(first, second, third, fourth, others))); + } + + /** + * Creates a new {@link GeoJsonPolygon} with an inner ring defined be the given {@link Point}s. + * + * @param first must not be {@literal null}. + * @param second must not be {@literal null}. + * @param third must not be {@literal null}. + * @param fourth must not be {@literal null}. + * @param others can be empty. + * @return new {@link GeoJsonPolygon}. + */ + public GeoJsonPolygon withInnerRing(Point first, Point second, Point third, Point fourth, Point... others) { + return withInnerRing(asList(first, second, third, fourth, others)); + } + + /** + * Creates a new {@link GeoJsonPolygon} with an inner ring defined be the given {@link GeoPoint}s. + * + * @param first must not be {@literal null}. + * @param second must not be {@literal null}. + * @param third must not be {@literal null}. + * @param fourth must not be {@literal null}. + * @param others can be empty. + * @return new {@link GeoJsonPolygon}. + */ + public GeoJsonPolygon withInnerRing(GeoPoint first, GeoPoint second, GeoPoint third, GeoPoint fourth, + GeoPoint... others) { + return withInnerRingOfGeoPoints(asList(first, second, third, fourth, others)); + } + + /** + * Creates a new {@link GeoJsonPolygon} with an inner ring defined be the given {@link List} of {@link Point}s. + * + * @param points must not be {@literal null}. + * @return new {@link GeoJsonPolygon}. + */ + public GeoJsonPolygon withInnerRing(List points) { + return withInnerRing(GeoJsonLineString.of(points)); + } + + /** + * Creates a new {@link GeoJsonPolygon} with an inner ring defined be the given {@link List} of {@link GeoPoint}s. + * + * @param geoPoints must not be {@literal null}. + * @return new {@link GeoJsonPolygon}. + */ + public GeoJsonPolygon withInnerRingOfGeoPoints(List geoPoints) { + return withInnerRing(GeoJsonLineString.ofGeoPoints(geoPoints)); + } + + /** + * Creates a new {@link GeoJsonPolygon} with an inner ring defined be the given {@link GeoJsonLineString}. + * + * @param lineString must not be {@literal null}. + * @return new {@link GeoJsonPolygon}. + * @since 1.10 + */ + public GeoJsonPolygon withInnerRing(GeoJsonLineString lineString) { + + Assert.notNull(lineString, "LineString must not be null!"); + + Iterator it = this.coordinates.iterator(); + GeoJsonPolygon polygon = new GeoJsonPolygon(it.next().getCoordinates()); + + while (it.hasNext()) { + polygon.coordinates.add(it.next()); + } + + polygon.coordinates.add(lineString); + return polygon; + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public List getCoordinates() { + return Collections.unmodifiableList(this.coordinates); + } + + @SafeVarargs + private static List asList(T first, T second, T third, T fourth, T... others) { + + ArrayList result = new ArrayList<>(3 + others.length); + + result.add(first); + result.add(second); + result.add(third); + result.add(fourth); + result.addAll(Arrays.asList(others)); + + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + GeoJsonPolygon that = (GeoJsonPolygon) o; + + return coordinates.equals(that.coordinates); + } + + @Override + public int hashCode() { + return coordinates.hashCode(); + } + + @Override + public String toString() { + return "GeoJsonPolygon{" + "coordinates=" + coordinates + '}'; + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/mapping/ElasticsearchPersistentProperty.java b/src/main/java/org/springframework/data/elasticsearch/core/mapping/ElasticsearchPersistentProperty.java index 63db55350..2f3523235 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/mapping/ElasticsearchPersistentProperty.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/mapping/ElasticsearchPersistentProperty.java @@ -126,6 +126,20 @@ public interface ElasticsearchPersistentProperty extends PersistentProperty getActualTypeOrNull() { + try { + return getActualType(); + } catch (Exception e) { + return null; + } + } + enum PropertyToFieldNameConverter implements Converter { INSTANCE; diff --git a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntity.java b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntity.java index 9d4308b5e..96bac20b7 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntity.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntity.java @@ -234,7 +234,8 @@ public class SimpleElasticsearchPersistentEntity extends BasicPersistentEntit } } - if (property.getActualType() == JoinField.class) { + Class actualType = property.getActualTypeOrNull(); + if (actualType == JoinField.class) { ElasticsearchPersistentProperty joinProperty = this.joinFieldProperty; if (joinProperty != null) { diff --git a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java index 33ff1ad0e..4b6eb3599 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java @@ -33,6 +33,7 @@ import org.springframework.data.elasticsearch.annotations.Parent; import org.springframework.data.elasticsearch.annotations.Score; import org.springframework.data.elasticsearch.core.completion.Completion; import org.springframework.data.elasticsearch.core.convert.ElasticsearchDateConverter; +import org.springframework.data.elasticsearch.core.geo.GeoJson; import org.springframework.data.elasticsearch.core.geo.GeoPoint; import org.springframework.data.elasticsearch.core.join.JoinField; import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm; @@ -148,7 +149,13 @@ public class SimpleElasticsearchPersistentProperty extends */ private void initDateConverter() { Field field = findAnnotation(Field.class); - Class actualType = getActualType(); + + Class actualType = getActualTypeOrNull(); + + if (actualType == null) { + return; + } + boolean isTemporalAccessor = TemporalAccessor.class.isAssignableFrom(actualType); boolean isDate = Date.class.isAssignableFrom(actualType); @@ -262,7 +269,7 @@ public class SimpleElasticsearchPersistentProperty extends @Override public boolean isGeoShapeProperty() { - return isAnnotationPresent(GeoShapeField.class); + return GeoJson.class.isAssignableFrom(getActualType()) || isAnnotationPresent(GeoShapeField.class); } @Override diff --git a/src/test/java/org/springframework/data/elasticsearch/config/namespace/ElasticsearchNamespaceHandlerTests.java b/src/test/java/org/springframework/data/elasticsearch/config/namespace/ElasticsearchNamespaceHandlerTests.java index e25a9a466..47027e26e 100644 --- a/src/test/java/org/springframework/data/elasticsearch/config/namespace/ElasticsearchNamespaceHandlerTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/config/namespace/ElasticsearchNamespaceHandlerTests.java @@ -17,6 +17,7 @@ package org.springframework.data.elasticsearch.config.namespace; import static org.assertj.core.api.Assertions.*; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -25,6 +26,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.client.RestClientFactoryBean; import org.springframework.data.elasticsearch.client.TransportClientFactoryBean; +import org.springframework.data.elasticsearch.junit.jupiter.Tags; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -38,6 +40,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; @ExtendWith(SpringExtension.class) @ContextConfiguration("namespace.xml") +@Tag(Tags.INTEGRATION_TEST) public class ElasticsearchNamespaceHandlerTests { @Autowired private ApplicationContext context; diff --git a/src/test/java/org/springframework/data/elasticsearch/core/convert/GeoConvertersUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/core/convert/GeoConvertersUnitTests.java new file mode 100644 index 000000000..476454293 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/convert/GeoConvertersUnitTests.java @@ -0,0 +1,400 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.convert; + +import static org.assertj.core.api.Assertions.*; +import static org.skyscreamer.jsonassert.JSONAssert.*; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.json.JSONException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.data.elasticsearch.core.document.Document; +import org.springframework.data.elasticsearch.core.geo.GeoJson; +import org.springframework.data.elasticsearch.core.geo.GeoJsonGeometryCollection; +import org.springframework.data.elasticsearch.core.geo.GeoJsonLineString; +import org.springframework.data.elasticsearch.core.geo.GeoJsonMultiLineString; +import org.springframework.data.elasticsearch.core.geo.GeoJsonMultiPoint; +import org.springframework.data.elasticsearch.core.geo.GeoJsonMultiPolygon; +import org.springframework.data.elasticsearch.core.geo.GeoJsonPoint; +import org.springframework.data.elasticsearch.core.geo.GeoJsonPolygon; +import org.springframework.data.geo.Point; + +/** + * @author Peter-Josef Meisch + */ +class GeoConvertersUnitTests { + + @Nested + @DisplayName("GeoJson Converters") + class GeoJsonTests { + + private final GeoConverters.GeoJsonToMapConverter geoJsonToMapConverter = GeoConverters.GeoJsonToMapConverter.INSTANCE; + private final GeoConverters.MapToGeoJsonConverter mapToGeoJsonConverter = GeoConverters.MapToGeoJsonConverter.INSTANCE; + + @Nested + @DisplayName("GeoJsonPoint") + class GeoJsonPointUnitTests { + + @Test // DATAES-930 + @DisplayName("should be converted to a Map") + void shouldBeConvertedToAMap() throws JSONException { + + String expected = "{\n" + // + " \"type\": \"Point\",\n" + // + " \"coordinates\": [12.0, 34.0]\n" + // + "}"; // + GeoJsonPoint geoJsonPoint = GeoJsonPoint.of(12, 34); + + Map map = geoJsonToMapConverter.convert(geoJsonPoint); + String json = Document.from(map).toJson(); + + assertEquals(expected, json, false); + } + + @Test // DATAES-930 + @DisplayName("should be converted from a Map") + void shouldBeConvertedFromAMap() { + + // make sure we can read int values as well + String json = "{\n" + // + " \"type\": \"Point\",\n" + // + " \"coordinates\": [12, 34.0]\n" + // + "}"; // + + Document document = Document.parse(json); + GeoJsonPoint expected = GeoJsonPoint.of(12, 34); + + GeoJson> geoJsonPoint = mapToGeoJsonConverter.convert(document); + + assertThat(geoJsonPoint).isInstanceOf(GeoJsonPoint.class).isEqualTo(expected); + } + } + + @Nested + @DisplayName("GeoJsonMultiPoint") + class GeoJsonMultipointUnitTests { + + @Test // DATAES-930 + @DisplayName("should be converted to a Map") + void shouldBeConvertedToAMap() throws JSONException { + + String expected = "{\n" + // + " \"type\": \"MultiPoint\",\n" + // + " \"coordinates\": [\n" + // + " [12.0, 34.0],\n" + // + " [56.0, 78.0]\n" + // + " ]\n" + // + "}\n"; // + + GeoJsonMultiPoint geoJsonMultiPoint = GeoJsonMultiPoint.of(new Point(12, 34), new Point(56, 78)); + + Map map = geoJsonToMapConverter.convert(geoJsonMultiPoint); + String json = Document.from(map).toJson(); + + assertEquals(expected, json, false); + } + + @Test // DATAES-930 + @DisplayName("should be converted from a Map") + void shouldBeConvertedFromAMap() { + + // make sure we can read int values as well + String json = "{\n" + " \"type\": \"MultiPoint\",\n" + " \"coordinates\": [\n" + " [12.0, 34],\n" + + " [56, 78.0]\n" + " ]\n" + "}\n"; + Document document = Document.parse(json); + + GeoJsonMultiPoint expected = GeoJsonMultiPoint.of(new Point(12, 34), new Point(56, 78)); + GeoJson> geoJsonMultiPoint = mapToGeoJsonConverter.convert(document); + + assertThat(geoJsonMultiPoint).isInstanceOf(GeoJsonMultiPoint.class).isEqualTo(expected); + } + } + + @Nested + @DisplayName("GeoJsonLineString") + class GeoJsonLineStringUnitTests { + + @Test // DATAES-930 + @DisplayName("should be converted to a Map") + void shouldBeConvertedToAMap() throws JSONException { + + String expected = "{\n" + // + " \"type\": \"LineString\",\n" + // + " \"coordinates\": [\n" + // + " [12.0, 34.0],\n" + // + " [56.0, 78.0]\n" + // + " ]\n" + // + "}\n"; // + + GeoJsonLineString geoJsonLineString = GeoJsonLineString.of(new Point(12, 34), new Point(56, 78)); + + Map map = geoJsonToMapConverter.convert(geoJsonLineString); + String json = Document.from(map).toJson(); + + assertEquals(expected, json, false); + } + + @Test // DATAES-930 + @DisplayName("should be converted from a Map") + void shouldBeConvertedFromAMap() { + + // make sure we can read int values as well + String json = "{\n" + // + " \"type\": \"LineString\",\n" + // + " \"coordinates\": [\n" + // + " [12.0, 34],\n" + // + " [56, 78.0]\n" // + + " ]\n" // + + "}\n"; // + Document document = Document.parse(json); + + GeoJsonLineString expected = GeoJsonLineString.of(new Point(12, 34), new Point(56, 78)); + GeoJson> geoJsonLineString = mapToGeoJsonConverter.convert(document); + + assertThat(geoJsonLineString).isInstanceOf(GeoJsonLineString.class).isEqualTo(expected); + } + } + + @Nested + @DisplayName("GeoJsonMultiLineString") + class GeoJsonMultiLineStringUnitTests { + + @Test // DATAES-930 + @DisplayName("should be converted to a Map") + void shouldBeConvertedToAMap() throws JSONException { + String expected = "{\n" + // + " \"type\": \"MultiLineString\",\n" + // + " \"coordinates\": [\n" + // + " [[12.0, 34.0], [56.0, 78.0]],\n" + // + " [[90.0, 12.0], [34.0, 56.0]]\n" + // + " ]\n" + // + "}\n"; // + + List lines = Arrays.asList( // + GeoJsonLineString.of(new Point(12, 34), new Point(56, 78)), // + GeoJsonLineString.of(new Point(90, 12), new Point(34, 56)) // + ); + GeoJsonMultiLineString geoJsonLineString = GeoJsonMultiLineString.of(lines); + + Map map = geoJsonToMapConverter.convert(geoJsonLineString); + String json = Document.from(map).toJson(); + + assertEquals(expected, json, false); + } + + @Test // DATAES-930 + @DisplayName("should be converted from a Map") + void shouldBeConvertedFromAMap() { + // make sure we can read int values as well + String json = "{\n" + // + " \"type\": \"MultiLineString\",\n" + // + " \"coordinates\": [\n" + // + " [[12, 34.0], [56.0, 78]],\n" + // + " [[90.0, 12], [34, 56.0]]\n" + // + " ]\n" + // + "}\n"; // + Document document = Document.parse(json); + List lines = Arrays.asList( // + GeoJsonLineString.of(new Point(12, 34), new Point(56, 78)), // + GeoJsonLineString.of(new Point(90, 12), new Point(34, 56)) // + ); + GeoJsonMultiLineString expected = GeoJsonMultiLineString.of(lines); + + GeoJson> geoJsonLineString = mapToGeoJsonConverter.convert(document); + + assertThat(geoJsonLineString).isInstanceOf(GeoJsonMultiLineString.class).isEqualTo(expected); + } + } + + @Nested + @DisplayName("GeoJsonPolygon") + class GeoJsonPolygonUnitTests { + + @Test // DATAES-930 + @DisplayName("should be converted to a Map") + void shouldBeConvertedToAMap() throws JSONException { + String expected = "{\n" + // + " \"type\": \"Polygon\",\n" + // + " \"coordinates\": [\n" + // + " [[12.0, 34.0], [56.0, 78.0], [90.0, 12.0], [12.0, 34.0]],\n" + // + " [[56.0, 78.0], [90.0, 12.0], [34.0, 56.0], [56.0, 78.0]]\n" + // + " ]\n" + // + "}\n"; // + + GeoJsonLineString polygonLineString = GeoJsonLineString.of(new Point(12, 34), new Point(56, 78), + new Point(90, 12), new Point(12, 34)); + GeoJsonLineString innerRingLineString = GeoJsonLineString.of(new Point(56, 78), new Point(90, 12), + new Point(34, 56), new Point(56, 78)); + GeoJsonPolygon geoJsonPolygon = GeoJsonPolygon.of(polygonLineString).withInnerRing(innerRingLineString); + + Map map = geoJsonToMapConverter.convert(geoJsonPolygon); + String json = Document.from(map).toJson(); + + assertEquals(expected, json, false); + } + + @Test // DATAES-930 + @DisplayName("should be converted from a Map") + void shouldBeConvertedFromAMap() { + + String json = "{\n" + // + " \"type\": \"Polygon\",\n" + // + " \"coordinates\": [\n" + // + " [[12, 34.0], [56.0, 78], [90, 12.0], [12, 34.0]],\n" + // + " [[56.0, 78], [90, 12.0], [34.0, 56], [56.0, 78]]\n" + // + " ]\n" + // + "}\n"; // + Document document = Document.parse(json); + GeoJsonLineString polygonLineString = GeoJsonLineString.of(new Point(12, 34), new Point(56, 78), + new Point(90, 12), new Point(12, 34)); + GeoJsonLineString innerRingLineString = GeoJsonLineString.of(new Point(56, 78), new Point(90, 12), + new Point(34, 56), new Point(56, 78)); + GeoJsonPolygon expected = GeoJsonPolygon.of(polygonLineString).withInnerRing(innerRingLineString); + + GeoJson> geoJsonLineString = mapToGeoJsonConverter.convert(document); + + assertThat(geoJsonLineString).isInstanceOf(GeoJsonPolygon.class).isEqualTo(expected); + } + } + + @Nested + @DisplayName("GeoJsonMultiPolygon") + class GeoJsonMultiPolygonUnitTests { + + @Test // DATAES-390 + @DisplayName("should be converted to a Map") + void shouldBeConvertedToAMap() throws JSONException { + String expected = "{\n" + // + " \"type\": \"MultiPolygon\",\n" + // + " \"coordinates\": [\n" + // + " [[[12.0, 34.0], [56.0, 78.0], [90.0, 12.0], [12.0, 34.0]]],\n" + // + " [[[56.0, 78.0], [90.0, 12.0], [34.0, 56.0], [56.0, 78.0]]]\n" + // + " ]\n" + // + "}\n"; // + + GeoJsonLineString polygonLineString1 = GeoJsonLineString.of(new Point(12, 34), new Point(56, 78), + new Point(90, 12), new Point(12, 34)); + GeoJsonLineString polygonLineString2 = GeoJsonLineString.of(new Point(56, 78), new Point(90, 12), + new Point(34, 56), new Point(56, 78)); + GeoJsonMultiPolygon geoJsonMultiPolygon = GeoJsonMultiPolygon + .of(Arrays.asList(GeoJsonPolygon.of(polygonLineString1), GeoJsonPolygon.of(polygonLineString2))); + + Map map = geoJsonToMapConverter.convert(geoJsonMultiPolygon); + String json = Document.from(map).toJson(); + + assertEquals(expected, json, false); + } + + @Test // DATAES-930 + @DisplayName("should be converted from a Map") + void shouldBeConvertedFromAMap() { + + String json = "{\n" + // + " \"type\": \"MultiPolygon\",\n" + // + " \"coordinates\": [\n" + // + " [[[12, 34.0], [56.0, 78], [90, 12.0], [12, 34.0]]],\n" + // + " [[[56, 78.0], [90, 12.0], [34.0, 56], [56, 78.0]]]\n" + // + " ]\n" + // + "}\n"; // + Document document = Document.parse(json); + GeoJsonLineString polygonLineString1 = GeoJsonLineString.of(new Point(12, 34), new Point(56, 78), + new Point(90, 12), new Point(12, 34)); + GeoJsonLineString polygonLineString2 = GeoJsonLineString.of(new Point(56, 78), new Point(90, 12), + new Point(34, 56), new Point(56, 78)); + GeoJsonMultiPolygon expected = GeoJsonMultiPolygon + .of(Arrays.asList(GeoJsonPolygon.of(polygonLineString1), GeoJsonPolygon.of(polygonLineString2))); + + GeoJson> geoJsonMultiPolygon = mapToGeoJsonConverter.convert(document); + + assertThat(geoJsonMultiPolygon).isInstanceOf(GeoJsonMultiPolygon.class).isEqualTo(expected); + } + } + + @Nested + @DisplayName("GeoJsonGeometryCollection") + class GeoJsonGeometryCollectionUnitTests { + + @Test // DATAES-930 + @DisplayName("should be converted to a Map") + void shouldBeConvertedToAMap() throws JSONException { + + String expected = "{\n" + // + " \"type\": \"GeometryCollection\",\n" + // + " \"geometries\": [\n" + // + " {\n" + // + " \"type\": \"Point\",\n" + // + " \"coordinates\": [12.0, 34.0]\n" + // + " },\n" + // + " {\n" + // + " \"type\": \"Polygon\",\n" + // + " \"coordinates\": [\n" + // + " [[12.0, 34.0], [56.0, 78.0], [90.0, 12.0], [12.0, 34.0]]\n" + // + " ]\n" + // + " }\n" + // + " ]\n" + // + "}\n"; // + GeoJsonPoint geoJsonPoint = GeoJsonPoint.of(12, 34); + GeoJsonPolygon geoJsonPolygon = GeoJsonPolygon + .of(GeoJsonLineString.of(new Point(12, 34), new Point(56, 78), new Point(90, 12), new Point(12, 34))); + + GeoJsonGeometryCollection geoJsonGeometryCollection = GeoJsonGeometryCollection + .of(Arrays.asList(geoJsonPoint, geoJsonPolygon)); + + Map map = geoJsonToMapConverter.convert(geoJsonGeometryCollection); + String json = Document.from(map).toJson(); + + assertEquals(expected, json, false); + } + + @Test // DATAES-930 + @DisplayName("should be converted from a Map") + void shouldBeConvertedFromAMap() { + + String json = "{\n" + // + " \"type\": \"GeometryCollection\",\n" + // + " \"geometries\": [\n" + // + " {\n" + // + " \"type\": \"Point\",\n" + // + " \"coordinates\": [12.0, 34.0]\n" + // + " },\n" + // + " {\n" + // + " \"type\": \"Polygon\",\n" + // + " \"coordinates\": [\n" + // + " [[12.0, 34.0], [56.0, 78.0], [90.0, 12.0], [12.0, 34.0]]\n" + // + " ]\n" + // + " }\n" + // + " ]\n" + // + "}\n"; // + Document document = Document.parse(json); + GeoJsonPoint geoJsonPoint = GeoJsonPoint.of(12, 34); + GeoJsonPolygon geoJsonPolygon = GeoJsonPolygon + .of(GeoJsonLineString.of(new Point(12, 34), new Point(56, 78), new Point(90, 12), new Point(12, 34))); + + GeoJsonGeometryCollection expected = GeoJsonGeometryCollection.of(Arrays.asList(geoJsonPoint, geoJsonPolygon)); + + GeoJson> geoJsonGeometryCollection = mapToGeoJsonConverter.convert(document); + + assertThat(geoJsonGeometryCollection).isInstanceOf(GeoJsonGeometryCollection.class).isEqualTo(expected); + + } + } + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverterUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverterUnitTests.java index 5efa825c1..6033ed6ef 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverterUnitTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverterUnitTests.java @@ -41,6 +41,7 @@ import java.util.Map; import org.json.JSONException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.converter.Converter; @@ -56,6 +57,14 @@ import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType; import org.springframework.data.elasticsearch.annotations.GeoPointField; import org.springframework.data.elasticsearch.core.document.Document; +import org.springframework.data.elasticsearch.core.geo.GeoJsonEntity; +import org.springframework.data.elasticsearch.core.geo.GeoJsonGeometryCollection; +import org.springframework.data.elasticsearch.core.geo.GeoJsonLineString; +import org.springframework.data.elasticsearch.core.geo.GeoJsonMultiLineString; +import org.springframework.data.elasticsearch.core.geo.GeoJsonMultiPoint; +import org.springframework.data.elasticsearch.core.geo.GeoJsonMultiPolygon; +import org.springframework.data.elasticsearch.core.geo.GeoJsonPoint; +import org.springframework.data.elasticsearch.core.geo.GeoJsonPolygon; import org.springframework.data.elasticsearch.core.geo.GeoPoint; import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext; import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm; @@ -889,6 +898,300 @@ public class MappingElasticsearchConverterUnitTests { assertEquals(expected, document.toJson(), false); } + @Nested + class GeoJsonUnitTests { + private GeoJsonEntity entity; + + @BeforeEach + void setup() { + GeoJsonMultiLineString multiLineString = GeoJsonMultiLineString.of(Arrays.asList( // + GeoJsonLineString.of(new Point(12, 34), new Point(56, 78)), // + GeoJsonLineString.of(new Point(90, 12), new Point(34, 56)) // + )); + GeoJsonPolygon geoJsonPolygon = GeoJsonPolygon // + .of(new Point(12, 34), new Point(56, 78), new Point(90, 12), new Point(12, 34)) // + .withInnerRing(new Point(21, 43), new Point(65, 87), new Point(9, 21), new Point(21, 43)); + GeoJsonMultiPolygon geoJsonMultiPolygon = GeoJsonMultiPolygon.of( + Arrays.asList(GeoJsonPolygon.of(new Point(12, 34), new Point(56, 78), new Point(90, 12), new Point(12, 34)), + GeoJsonPolygon.of(new Point(21, 43), new Point(65, 87), new Point(9, 21), new Point(21, 43)))); + GeoJsonPoint geoJsonPoint = GeoJsonPoint.of(12, 34); + GeoJsonGeometryCollection geoJsonGeometryCollection = GeoJsonGeometryCollection + .of(Arrays.asList(GeoJsonPoint.of(12, 34), GeoJsonPolygon + .of(GeoJsonLineString.of(new Point(12, 34), new Point(56, 78), new Point(90, 12), new Point(12, 34))))); + + entity = GeoJsonEntity.builder() // + .id("42") // + .point1(GeoJsonPoint.of(12, 34)) // + .point2(GeoJsonPoint.of(56, 78)) // + .multiPoint1(GeoJsonMultiPoint.of(new Point(12, 34), new Point(56, 78), new Point(90, 12))) // + .multiPoint2(GeoJsonMultiPoint.of(new Point(90, 12), new Point(56, 78), new Point(12, 34))) // + .lineString1(GeoJsonLineString.of(new Point(12, 34), new Point(56, 78), new Point(90, 12))) // + .lineString2(GeoJsonLineString.of(new Point(90, 12), new Point(56, 78), new Point(12, 34))) // + .multiLineString1(multiLineString) // + .multiLineString2(multiLineString) // + .polygon1(geoJsonPolygon) // + .polygon2(geoJsonPolygon) // + .multiPolygon1(geoJsonMultiPolygon) // + .multiPolygon2(geoJsonMultiPolygon) // + .geometryCollection1(geoJsonGeometryCollection) // + .geometryCollection2(geoJsonGeometryCollection) // + .build(); + } + + @Test // DATAES-930 + @DisplayName("should write GeoJson properties") + void shouldWriteGeoJsonProperties() throws JSONException { + + String json = "{\n" + // + " \"id\": \"42\",\n" + // + " \"point1\": {\n" + // + " \"type\": \"Point\",\n" + // + " \"coordinates\": [12.0, 34.0]\n" + // + " },\n" + // + " \"point2\": {\n" + // + " \"type\": \"Point\",\n" + // + " \"coordinates\": [56.0, 78.0]\n" + // + " },\n" + // + " \"multiPoint1\": {\n" + // + " \"type\": \"MultiPoint\",\n" + // + " \"coordinates\": [\n" + // + " [12.0, 34.0],\n" + // + " [56.0, 78.0],\n" + // + " [90.0, 12.0]\n" + // + " ]\n" + // + " },\n" + // + " \"multiPoint2\": {\n" + // + " \"type\": \"MultiPoint\",\n" + // + " \"coordinates\": [\n" + // + " [90.0, 12.0],\n" + // + " [56.0, 78.0],\n" + // + " [12.0, 34.0]\n" + // + " ]\n" + // + " },\n" + // + " \"lineString1\": {\n" + // + " \"type\": \"LineString\",\n" + // + " \"coordinates\": [\n" + // + " [12.0, 34.0],\n" + // + " [56.0, 78.0],\n" + // + " [90.0, 12.0]\n" + // + " ]\n" + // + " },\n" + // + " \"lineString2\": {\n" + // + " \"type\": \"LineString\",\n" + // + " \"coordinates\": [\n" + // + " [90.0, 12.0],\n" + // + " [56.0, 78.0],\n" + // + " [12.0, 34.0]\n" + // + " ]\n" + // + " },\n" + // + " \"multiLineString1\":{\n" + // + " \"type\": \"MultiLineString\",\n" + // + " \"coordinates\": [\n" + // + " [[12.0, 34.0], [56.0, 78.0]],\n" + // + " [[90.0, 12.0], [34.0, 56.0]]\n" + // + " ]\n" + // + " },\n" + // + " \"multiLineString2\":{\n" + // + " \"type\": \"MultiLineString\",\n" + // + " \"coordinates\": [\n" + // + " [[12.0, 34.0], [56.0, 78.0]],\n" + // + " [[90.0, 12.0], [34.0, 56.0]]\n" + // + " ]\n" + // + " },\n" + // + " \"polygon1\":{\n" + // + " \"type\": \"Polygon\",\n" + // + " \"coordinates\": [\n" + // + " [[12.0, 34.0],[56.0, 78.0],[90.0, 12.0],[12.0, 34.0]],\n" + // + " [[21.0, 43.0],[65.0, 87.0],[9.0, 21.0],[21.0, 43.0]]\n" + // + " ]\n" + // + " },\n" + // + " \"polygon2\":{\n" + // + " \"type\": \"Polygon\",\n" + // + " \"coordinates\": [\n" + // + " [[12.0, 34.0],[56.0, 78.0],[90.0, 12.0],[12.0, 34.0]],\n" + // + " [[21.0, 43.0],[65.0, 87.0],[9.0, 21.0],[21.0, 43.0]]\n" + // + " ]\n" + // + " },\n" + // + " \"multiPolygon1\":{\n" + // + " \"type\": \"MultiPolygon\",\n" + // + " \"coordinates\": [\n" + // + " [[[12.0, 34.0],[56.0, 78.0],[90.0, 12.0],[12.0, 34.0]]],\n" + // + " [[[21.0, 43.0],[65.0, 87.0],[9.0, 21.0],[21.0, 43.0]]]\n" + // + " ]\n" + // + " },\n" + // + " \"multiPolygon2\":{\n" + // + " \"type\": \"MultiPolygon\",\n" + // + " \"coordinates\": [\n" + // + " [[[12.0, 34.0],[56.0, 78.0],[90.0, 12.0],[12.0, 34.0]]],\n" + // + " [[[21.0, 43.0],[65.0, 87.0],[9.0, 21.0],[21.0, 43.0]]]\n" + // + " ]\n" + // + " },\n" + // + " \"geometryCollection1\": {\n" + // + " \"type\": \"GeometryCollection\",\n" + // + " \"geometries\": [\n" + // + " {\n" + // + " \"type\": \"Point\",\n" + // + " \"coordinates\": [12.0, 34.0]\n" + // + " },\n" + // + " {\n" + // + " \"type\": \"Polygon\",\n" + // + " \"coordinates\": [\n" + // + " [[12.0, 34.0], [56.0, 78.0], [90.0, 12.0], [12.0, 34.0]]\n" + // + " ]\n" + // + " }\n" + // + " ]\n" + // + " },\n" + // + " \"geometryCollection2\": {\n" + // + " \"type\": \"GeometryCollection\",\n" + // + " \"geometries\": [\n" + // + " {\n" + // + " \"type\": \"Point\",\n" + // + " \"coordinates\": [12.0, 34.0]\n" + // + " },\n" + // + " {\n" + // + " \"type\": \"Polygon\",\n" + // + " \"coordinates\": [\n" + // + " [[12.0, 34.0], [56.0, 78.0], [90.0, 12.0], [12.0, 34.0]]\n" + // + " ]\n" + // + " }\n" + // + " ]\n" + // + " }\n" + // + "}\n"; // + + Document document = Document.create(); + + mappingElasticsearchConverter.write(entity, document); + + assertEquals(json, document.toJson(), false); + } + + @Test // DATAES-930 + @DisplayName("should read GeoJson properties") + void shouldReadGeoJsonProperties() { + + // make sure we can read int values as well + String json = "{\n" + // + " \"id\": \"42\",\n" + // + " \"point1\": {\n" + // + " \"type\": \"Point\",\n" + // + " \"coordinates\": [12, 34]\n" + // + " },\n" + // + " \"point2\": {\n" + // + " \"type\": \"Point\",\n" + // + " \"coordinates\": [56, 78]\n" + // + " },\n" + // + " \"multiPoint1\": {\n" + // + " \"type\": \"MultiPoint\",\n" + // + " \"coordinates\": [\n" + // + " [12.0, 34],\n" + // + " [56, 78.0],\n" + // + " [90, 12.0]\n" + // + " ]\n" + // + " },\n" + // + " \"multiPoint2\": {\n" + // + " \"type\": \"MultiPoint\",\n" + // + " \"coordinates\": [\n" + // + " [90, 12.0],\n" + // + " [56, 78.0],\n" + // + " [12.0, 34]\n" + // + " ]\n" + // + " },\n" + // + " \"lineString1\": {\n" + // + " \"type\": \"LineString\",\n" + // + " \"coordinates\": [\n" + // + " [12.0, 34],\n" + // + " [56, 78.0],\n" + // + " [90, 12.0]\n" + // + " ]\n" + // + " },\n" + // + " \"lineString2\": {\n" + // + " \"type\": \"LineString\",\n" + // + " \"coordinates\": [\n" + // + " [90, 12.0],\n" + // + " [56, 78.0],\n" + // + " [12.0, 34]\n" + // + " ]\n" + // + " },\n" + // + " \"multiLineString1\":{\n" + // + " \"type\": \"MultiLineString\",\n" + // + " \"coordinates\": [\n" + // + " [[12, 34.0], [56, 78.0]],\n" + // + " [[90.0, 12], [34.0, 56]]\n" + // + " ]\n" + // + " },\n" + // + " \"multiLineString2\":{\n" + // + " \"type\": \"MultiLineString\",\n" + // + " \"coordinates\": [\n" + // + " [[12.0, 34], [56.0, 78]],\n" + // + " [[90, 12.0], [34, 56.0]]\n" + // + " ]\n" + // + " },\n" + // + " \"polygon1\":{\n" + // + " \"type\": \"Polygon\",\n" + // + " \"coordinates\": [\n" + // + " [[12, 34.0],[56.0, 78],[90, 12.0],[12.0, 34]],\n" + // + " [[21.0, 43],[65, 87.0],[9.0, 21],[21, 43.0]]\n" + // + " ]\n" + // + " },\n" + // + " \"polygon2\":{\n" + // + " \"type\": \"Polygon\",\n" + // + " \"coordinates\": [\n" + // + " [[12, 34.0],[56.0, 78],[90, 12.0],[12.0, 34]],\n" + // + " [[21.0, 43],[65, 87.0],[9.0, 21],[21, 43.0]]\n" + // + " ]\n" + // + " },\n" + // + " \"multiPolygon1\":{\n" + // + " \"type\": \"MultiPolygon\",\n" + // + " \"coordinates\": [\n" + // + " [[[12, 34.0],[56.0, 78],[90, 12.0],[12.0, 34]]],\n" + // + " [[[21.0, 43],[65, 87.0],[9.0, 21],[21, 43.0]]]\n" + // + " ]\n" + // + " },\n" + // + " \"multiPolygon2\":{\n" + // + " \"type\": \"MultiPolygon\",\n" + // + " \"coordinates\": [\n" + // + " [[[12, 34.0],[56.0, 78],[90, 12.0],[12.0, 34]]],\n" + // + " [[[21.0, 43],[65, 87.0],[9.0, 21],[21, 43.0]]]\n" + // + " ]\n" + // + " },\n" + // + " \"geometryCollection1\": {\n" + // + " \"type\": \"GeometryCollection\",\n" + // + " \"geometries\": [\n" + // + " {\n" + // + " \"type\": \"Point\",\n" + // + " \"coordinates\": [12, 34.0]\n" + // + " },\n" + // + " {\n" + // + " \"type\": \"Polygon\",\n" + // + " \"coordinates\": [\n" + // + " [[12.0, 34], [56, 78.0], [90.0, 12], [12, 34.0]]\n" + // + " ]\n" + // + " }\n" + // + " ]\n" + // + " },\n" + // + " \"geometryCollection2\": {\n" + // + " \"type\": \"GeometryCollection\",\n" + // + " \"geometries\": [\n" + // + " {\n" + // + " \"type\": \"Point\",\n" + // + " \"coordinates\": [12, 34.0]\n" + // + " },\n" + // + " {\n" + // + " \"type\": \"Polygon\",\n" + // + " \"coordinates\": [\n" + // + " [[12.0, 34], [56, 78.0], [90.0, 12], [12, 34.0]]\n" + // + " ]\n" + // + " }\n" + // + " ]\n" + // + " }\n" + // + "}\n"; // + + GeoJsonEntity mapped = mappingElasticsearchConverter.read(GeoJsonEntity.class, Document.parse(json)); + + assertThat(entity).isEqualTo(mapped); + } + } + private String pointTemplate(String name, Point point) { return String.format(Locale.ENGLISH, "\"%s\":{\"lat\":%.1f,\"lon\":%.1f}", name, point.getY(), point.getX()); } @@ -1138,4 +1441,5 @@ public class MappingElasticsearchConverterUnitTests { @Field(type = FieldType.Text) private String notSaved; @Field(type = FieldType.Text, storeNullValue = true) private String saved; } + } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonEntity.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonEntity.java new file mode 100644 index 000000000..12d71f8df --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonEntity.java @@ -0,0 +1,47 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import lombok.Builder; +import lombok.Data; + +import org.springframework.data.annotation.Id; +import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.geo.Point; + +/** + * this class contains each GeoJson type as explicit type and as GeoJson interface. Used by several test classes + */ +@Data +@Builder +@Document(indexName = "geojson-index") +public class GeoJsonEntity { + @Id private String id; + GeoJsonPoint point1; + GeoJson> point2; + GeoJsonMultiPoint multiPoint1; + GeoJson> multiPoint2; + GeoJsonLineString lineString1; + GeoJson> lineString2; + GeoJsonMultiLineString multiLineString1; + GeoJson> multiLineString2; + GeoJsonPolygon polygon1; + GeoJson> polygon2; + GeoJsonMultiPolygon multiPolygon1; + GeoJson> multiPolygon2; + GeoJsonGeometryCollection geometryCollection1; + GeoJson>> geometryCollection2; +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonGeometryCollectionUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonGeometryCollectionUnitTests.java new file mode 100644 index 000000000..23acf6210 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonGeometryCollectionUnitTests.java @@ -0,0 +1,44 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import static org.assertj.core.api.Assertions.*; + +import java.util.Arrays; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.data.geo.Point; + +/** + * @author Peter-Josef Meisch + */ +class GeoJsonGeometryCollectionUnitTests { + + @Test // DATAES-930 + @DisplayName("should accept a list of GeoJson objects") + void shouldAcceptAListOfGeoJsonObjects() { + + GeoJsonPoint geoJsonPoint = GeoJsonPoint.of(12, 34); + GeoJsonPolygon geoJsonPolygon = GeoJsonPolygon + .of(GeoJsonLineString.of(new Point(12, 34), new Point(56, 78), new Point(90, 12), new Point(12, 34))); + + GeoJsonGeometryCollection geoJsonGeometryCollection = GeoJsonGeometryCollection + .of(Arrays.asList(geoJsonPoint, geoJsonPolygon)); + + assertThat(geoJsonGeometryCollection.getGeometries()).containsExactly(geoJsonPoint, geoJsonPolygon); + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonIntegrationTest.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonIntegrationTest.java new file mode 100644 index 000000000..039d9320b --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonIntegrationTest.java @@ -0,0 +1,102 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import static org.assertj.core.api.Assertions.*; + +import java.util.Arrays; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.elasticsearch.core.ElasticsearchOperations; +import org.springframework.data.elasticsearch.core.IndexOperations; +import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration; +import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; +import org.springframework.data.geo.Point; +import org.springframework.test.context.ContextConfiguration; + +/** + * @author Peter-Josef Meisch + */ +@SpringIntegrationTest +@ContextConfiguration(classes = { ElasticsearchRestTemplateConfiguration.class }) +@DisplayName("GeoJson integration test with REST client") +class GeoJsonIntegrationTest { + + @Autowired private ElasticsearchOperations operations; + + private IndexOperations indexOps; + + @BeforeEach + void setUp() { + indexOps = operations.indexOps(GeoJsonEntity.class); + indexOps.delete(); + indexOps.create(); + indexOps.putMapping(); + } + + @AfterEach + void tearDown() { + indexOps.delete(); + } + + @Test // DATAES-930 + @DisplayName("should write and read an entity with GeoJson properties") + void shouldWriteAndReadAnEntityWithGeoJsonProperties() { + + GeoJsonMultiLineString multiLineString = GeoJsonMultiLineString.of(Arrays.asList( // + GeoJsonLineString.of(new Point(12, 34), new Point(56, 78)), // + GeoJsonLineString.of(new Point(90, 12), new Point(34, 56)) // + )); + GeoJsonPolygon geoJsonPolygon = GeoJsonPolygon + .of(new Point(12, 34), new Point(56, 78), new Point(90, 12), new Point(12, 34)) + .withInnerRing(new Point(21, 43), new Point(65, 87), new Point(9, 21), new Point(21, 43)); + GeoJsonMultiPolygon geoJsonMultiPolygon = GeoJsonMultiPolygon + .of(Arrays.asList(GeoJsonPolygon.of(new Point(12, 34), new Point(56, 78), new Point(90, 12), new Point(12, 34)), + GeoJsonPolygon.of(new Point(21, 43), new Point(65, 87), new Point(9, 21), new Point(21, 43)))); + GeoJsonGeometryCollection geoJsonGeometryCollection = GeoJsonGeometryCollection + .of(Arrays.asList(GeoJsonPoint.of(12, 34), GeoJsonPolygon + .of(GeoJsonLineString.of(new Point(12, 34), new Point(56, 78), new Point(90, 12), new Point(12, 34))))); + + GeoJsonEntity entity = GeoJsonEntity.builder() // + .id("42") // + .point1(GeoJsonPoint.of(12, 34)) // + .point2(GeoJsonPoint.of(56, 78)) // + .multiPoint1(GeoJsonMultiPoint.of(new Point(12, 34), new Point(56, 78), new Point(90, 12))) // + .multiPoint2(GeoJsonMultiPoint.of(new Point(90, 12), new Point(56, 78), new Point(12, 34))) // + .lineString1(GeoJsonLineString.of(new Point(12, 34), new Point(56, 78), new Point(90, 12))) // + .lineString2(GeoJsonLineString.of(new Point(90, 12), new Point(56, 78), new Point(12, 34))) // + .multiLineString1(multiLineString) // + .multiLineString2(multiLineString) // + .polygon1(geoJsonPolygon) // + .polygon2(geoJsonPolygon) // + .multiPolygon1(geoJsonMultiPolygon) // + .multiPolygon2(geoJsonMultiPolygon) // + .geometryCollection1(geoJsonGeometryCollection) // + .geometryCollection2(geoJsonGeometryCollection) // + .build(); // + + operations.save(entity); + indexOps.refresh(); + + GeoJsonEntity result = operations.get("42", GeoJsonEntity.class); + + assertThat(result).isEqualTo(entity); + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonLineStringUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonLineStringUnitTests.java new file mode 100644 index 000000000..07729073c --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonLineStringUnitTests.java @@ -0,0 +1,83 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import static org.assertj.core.api.Assertions.*; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.data.geo.Point; + +/** + * @author Peter-Josef Meisch + */ +class GeoJsonLineStringUnitTests { + + @Test // DATAES-930 + @DisplayName("should accept list of Point") + void shouldAcceptListOfPoint() { + + List points = Arrays.asList(new Point(12, 34), new Point(56, 78), new Point(90, 12)); + GeoJsonLineString geoJsonLineString = GeoJsonLineString.of(points); + + List coordinates = geoJsonLineString.getCoordinates(); + + assertThat(coordinates).containsExactlyElementsOf(points); + } + + @Test // DATAES-930 + @DisplayName("should accept array of Point") + void shouldAcceptVarargArrayOfPoint() { + Point[] points = new Point[] { new Point(12, 34), new Point(56, 78), new Point(90, 12) }; + + GeoJsonLineString geoJsonLineString = GeoJsonLineString.of(new Point(12, 34), new Point(56, 78), new Point(90, 12)); + + List coordinates = geoJsonLineString.getCoordinates(); + + assertThat(coordinates).containsExactly(points); + } + + @Test // DATAES-930 + @DisplayName("should accept list of GeoPoint") + void shouldAcceptListOfGeoPoint() { + + List points = Arrays.asList(new Point(12, 34), new Point(56, 78), new Point(90, 12)); + List geoPoints = points.stream().map(GeoPoint::fromPoint).collect(Collectors.toList()); + + GeoJsonLineString geoJsonLineString = GeoJsonLineString.ofGeoPoints(geoPoints); + + List coordinates = geoJsonLineString.getCoordinates(); + + assertThat(coordinates).containsExactlyElementsOf(points); + } + + @Test // DATAES-930 + @DisplayName("should accept array of Point") + void shouldAcceptVarargArrayOfGeoPoint() { + Point[] points = new Point[] { new Point(12, 34), new Point(56, 78), new Point(90, 12) }; + GeoPoint[] geoPoints = Arrays.stream(points).map(GeoPoint::fromPoint).toArray(value -> new GeoPoint[points.length]); + + GeoJsonLineString geoJsonLineString = GeoJsonLineString.of(geoPoints[0], geoPoints[1], geoPoints[2]); + + List coordinates = geoJsonLineString.getCoordinates(); + + assertThat(coordinates).containsExactly(points); + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiLineStringUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiLineStringUnitTests.java new file mode 100644 index 000000000..673ce4542 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiLineStringUnitTests.java @@ -0,0 +1,63 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import static org.assertj.core.api.Assertions.*; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.data.geo.Point; + +/** + * @author Peter-Josef Meisch + */ +class GeoJsonMultiLineStringUnitTests { + + @Test // DATAES-930 + @DisplayName("should accept list of GeoJsonLineString") + void shouldAcceptListOfGeoJsonLineString() { + + List lines = Arrays.asList( // + GeoJsonLineString.of(new Point(12, 34), new Point(56, 78)), // + GeoJsonLineString.of(new Point(90, 12), new Point(34, 56)) // + ); + + GeoJsonMultiLineString geoJsonMultiLineString = GeoJsonMultiLineString.of(lines); + Iterable coordinates = geoJsonMultiLineString.getCoordinates(); + + assertThat(coordinates).containsExactlyElementsOf(lines); + } + + @Test // DATAES-930 + @DisplayName("should accept an array of List of Point") + void shouldAcceptAnArrayOfListOfPoint() { + + List[] lists = new List[] { // + Arrays.asList(new Point(12, 34), new Point(56, 78)), // + Arrays.asList(new Point(90, 12), new Point(34, 56)) // + }; + List lines = Arrays.stream(lists).map(GeoJsonLineString::of).collect(Collectors.toList()); + + GeoJsonMultiLineString geoJsonMultiLineString = GeoJsonMultiLineString.of(lists); + Iterable coordinates = geoJsonMultiLineString.getCoordinates(); + + assertThat(coordinates).containsExactlyElementsOf(lines); + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPointUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPointUnitTests.java new file mode 100644 index 000000000..b65df3f2b --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPointUnitTests.java @@ -0,0 +1,84 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import static org.assertj.core.api.Assertions.*; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.data.geo.Point; + +/** + * @author Peter-Josef Meisch + */ +class GeoJsonMultiPointUnitTests { + + @Test // DATAES-930 + @DisplayName("should accept list of Point") + void shouldAcceptListOfPoint() { + + List points = Arrays.asList(new Point(12, 34), new Point(56, 78), new Point(90, 12)); + GeoJsonMultiPoint geoJsonMultiPoint = GeoJsonMultiPoint.of(points); + + List coordinates = geoJsonMultiPoint.getCoordinates(); + + assertThat(coordinates).containsExactlyElementsOf(points); + } + + @Test // DATAES-930 + @DisplayName("should accept array of Point") + void shouldAcceptVarargArrayOfPoint() { + Point[] points = new Point[] { new Point(12, 34), new Point(56, 78), new Point(90, 12) }; + + GeoJsonMultiPoint geoJsonMultiPoint = GeoJsonMultiPoint.of(new Point(12, 34), new Point(56, 78), new Point(90, 12)); + + List coordinates = geoJsonMultiPoint.getCoordinates(); + + assertThat(coordinates).containsExactly(points); + } + + @Test // DATAES-930 + @DisplayName("should accept list of GeoPoint") + void shouldAcceptListOfGeoPoint() { + + List points = Arrays.asList(new Point(12, 34), new Point(56, 78), new Point(90, 12)); + List geoPoints = points.stream().map(GeoPoint::fromPoint).collect(Collectors.toList()); + + GeoJsonMultiPoint geoJsonMultiPoint = GeoJsonMultiPoint.ofGeoPoints(geoPoints); + + List coordinates = geoJsonMultiPoint.getCoordinates(); + + assertThat(coordinates).containsExactlyElementsOf(points); + } + + @Test // DATAES-930 + @DisplayName("should accept array of Point") + void shouldAcceptVarargArrayOfGeoPoint() { + Point[] points = new Point[] { new Point(12, 34), new Point(56, 78), new Point(90, 12) }; + GeoPoint[] geoPoints = Arrays.stream(points).map(GeoPoint::fromPoint).toArray(value -> new GeoPoint[points.length]); + + GeoJsonMultiPoint geoJsonMultiPoint = GeoJsonMultiPoint.of(geoPoints[0], geoPoints[1], geoPoints[2]); + + List coordinates = geoJsonMultiPoint.getCoordinates(); + + assertThat(coordinates).containsExactly(points); + } + +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPolygonUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPolygonUnitTests.java new file mode 100644 index 000000000..2c56e7064 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonMultiPolygonUnitTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import static org.assertj.core.api.Assertions.*; + +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.data.geo.Point; + +/** + * @author Peter-Josef Meisch + */ +class GeoJsonMultiPolygonUnitTests { + + @Test // DATAES-930 + @DisplayName("should accept a list of GeoJsonPolygons") + void shouldAcceptAListOfGeoJsonPolygons() { + List pointList1 = Arrays.asList(new Point(12, 34), new Point(56, 78), new Point(90, 12), new Point(34, 56)); + List pointList2 = Arrays.asList(new Point(56, 78), new Point(90, 12), new Point(34, 56), new Point(12, 34)); + + GeoJsonPolygon geoJsonPolygon1 = GeoJsonPolygon.of(pointList1.get(0), pointList1.get(1), pointList1.get(2), + pointList1.get(3)); + GeoJsonPolygon geoJsonPolygon2 = GeoJsonPolygon.of(pointList2.get(0), pointList2.get(1), pointList2.get(2), + pointList2.get(3)); + + GeoJsonMultiPolygon geoJsonMultiPolygon = GeoJsonMultiPolygon.of(Arrays.asList(geoJsonPolygon1, geoJsonPolygon2)); + + assertThat(geoJsonMultiPolygon.getCoordinates()).containsExactly(geoJsonPolygon1, geoJsonPolygon2); + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPointUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPointUnitTests.java new file mode 100644 index 000000000..fe9d3e219 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPointUnitTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import static org.assertj.core.api.Assertions.*; + +import java.util.List; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.data.geo.Point; + +/** + * @author Peter-Josef Meisch + */ +class GeoJsonPointUnitTests { + + @Test // DATAES-930 + @DisplayName("should return x and y as coordinates") + void shouldReturnXAndYAsCoordinates() { + + GeoJsonPoint geoJsonPoint = GeoJsonPoint.of(12, 34); + + List coordinates = geoJsonPoint.getCoordinates(); + + assertThat(coordinates).containsExactly(12d, 34d); + } + + @Test // DATAES-930 + @DisplayName("should accept a Point as parameter") + void shouldAcceptAPointAsParameter() { + + GeoJsonPoint geoJsonPoint1 = GeoJsonPoint.of(12, 34); + GeoJsonPoint geoJsonPoint2 = GeoJsonPoint.of(new Point(12, 34)); + + assertThat(geoJsonPoint1).isEqualTo(geoJsonPoint2); + } + + @Test // DATAES-930 + @DisplayName("should accept a GeoPoint as parameter") + void shouldAcceptAGeoPointAsParameter() { + + GeoJsonPoint geoJsonPoint1 = GeoJsonPoint.of(12, 34); + GeoJsonPoint geoJsonPoint2 = GeoJsonPoint.of(new GeoPoint(34, 12)); + + assertThat(geoJsonPoint1).isEqualTo(geoJsonPoint2); + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPolygonUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPolygonUnitTests.java new file mode 100644 index 000000000..5a1e28ca3 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonPolygonUnitTests.java @@ -0,0 +1,95 @@ +package org.springframework.data.elasticsearch.core.geo; + +import static org.assertj.core.api.Assertions.*; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.data.geo.Point; + +/** + * @author Peter-Josef Meisch + */ +class GeoJsonPolygonUnitTests { + + @Test // DATAES-930 + @DisplayName("should accept a GeoJsonLineString") + void shouldAcceptAGeoJsonLineString() { + + GeoJsonLineString geoJsonLineString = GeoJsonLineString.of(new Point(12, 34), new Point(56, 78), new Point(90, 12), + new Point(34, 56)); + GeoJsonLineString innerRing = GeoJsonLineString.of(new Point(56, 78), new Point(90, 12), new Point(34, 56), + new Point(12, 34)); + + GeoJsonPolygon geoJsonPolygon = GeoJsonPolygon.of(geoJsonLineString).withInnerRing(innerRing); + + assertThat(geoJsonPolygon.getCoordinates()).containsExactly(geoJsonLineString, innerRing); + } + + @Test // DATES-930 + @DisplayName("should accept a list of Points") + void shouldAcceptAListOfPoints() { + + List pointList = Arrays.asList(new Point(12, 34), new Point(56, 78), new Point(90, 12), new Point(34, 56)); + List innerRingPointList = Arrays.asList(new Point(56, 78), new Point(90, 12), new Point(34, 56), + new Point(12, 34)); + + GeoJsonPolygon geoJsonPolygon = GeoJsonPolygon.of(pointList).withInnerRing(innerRingPointList); + + assertThat(geoJsonPolygon.getCoordinates()).containsExactly(GeoJsonLineString.of(pointList), + GeoJsonLineString.of(innerRingPointList)); + } + + @Test // DATES-930 + @DisplayName("should accept a list of GeoPoints") + void shouldAcceptAListOfGeoPoints() { + + List pointList = Arrays.asList(new Point(12, 34), new Point(56, 78), new Point(90, 12), new Point(34, 56)); + List innerRingPointList = Arrays.asList(new Point(56, 78), new Point(90, 12), new Point(34, 56), + new Point(12, 34)); + + GeoJsonPolygon geoJsonPolygon = GeoJsonPolygon + .ofGeoPoints(pointList.stream().map(GeoPoint::fromPoint).collect(Collectors.toList())) + .withInnerRingOfGeoPoints(innerRingPointList.stream().map(GeoPoint::fromPoint).collect(Collectors.toList())); + + assertThat(geoJsonPolygon.getCoordinates()).containsExactly(GeoJsonLineString.of(pointList), + GeoJsonLineString.of(innerRingPointList)); + } + + @Test // DATES-930 + @DisplayName("should accept an array of points") + void shouldAcceptAnArrayOfPoints() { + + List pointList = Arrays.asList(new Point(12, 34), new Point(56, 78), new Point(90, 12), new Point(34, 56)); + List innerRingPointList = Arrays.asList(new Point(56, 78), new Point(90, 12), new Point(34, 56), + new Point(12, 34)); + + GeoJsonPolygon geoJsonPolygon = GeoJsonPolygon + .of(pointList.get(0), pointList.get(1), pointList.get(2), pointList.get(3)).withInnerRing( + innerRingPointList.get(0), innerRingPointList.get(1), innerRingPointList.get(2), innerRingPointList.get(3)); + + assertThat(geoJsonPolygon.getCoordinates()).containsExactly(GeoJsonLineString.of(pointList), + GeoJsonLineString.of(innerRingPointList)); + } + + @Test // DATES-930 + @DisplayName("should accept an array of GeoPoints") + void shouldAcceptAnArrayOfGeoPoints() { + + List pointList = Arrays.asList(new Point(12, 34), new Point(56, 78), new Point(90, 12), new Point(34, 56)); + List innerRingPointList = Arrays.asList(new Point(56, 78), new Point(90, 12), new Point(34, 56), + new Point(12, 34)); + + GeoJsonPolygon geoJsonPolygon = GeoJsonPolygon + .of(GeoPoint.fromPoint(pointList.get(0)), GeoPoint.fromPoint(pointList.get(1)), + GeoPoint.fromPoint(pointList.get(2)), GeoPoint.fromPoint(pointList.get(3))) + .withInnerRing(GeoPoint.fromPoint(innerRingPointList.get(0)), GeoPoint.fromPoint(innerRingPointList.get(1)), + GeoPoint.fromPoint(innerRingPointList.get(2)), GeoPoint.fromPoint(innerRingPointList.get(3))); + + assertThat(geoJsonPolygon.getCoordinates()).containsExactly(GeoJsonLineString.of(pointList), + GeoJsonLineString.of(innerRingPointList)); + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonTransportIntegrationTest.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonTransportIntegrationTest.java new file mode 100644 index 000000000..6e2d47601 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoJsonTransportIntegrationTest.java @@ -0,0 +1,29 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.geo; + +import org.junit.jupiter.api.DisplayName; +import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration; +import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; +import org.springframework.test.context.ContextConfiguration; + +/** + * @author Peter-Josef Meisch + */ +@SpringIntegrationTest +@ContextConfiguration(classes = { ElasticsearchTemplateConfiguration.class }) +@DisplayName("GeoJson integration test with transport client") +public class GeoJsonTransportIntegrationTest extends GeoJsonIntegrationTest {} diff --git a/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ElasticsearchRestTemplateConfiguration.java b/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ElasticsearchRestTemplateConfiguration.java index 2a6b54633..9f3dc2a52 100644 --- a/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ElasticsearchRestTemplateConfiguration.java +++ b/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ElasticsearchRestTemplateConfiguration.java @@ -49,6 +49,12 @@ public class ElasticsearchRestTemplateConfiguration extends AbstractElasticsearc ClientConfiguration.TerminalClientConfigurationBuilder configurationBuilder = ClientConfiguration.builder() .connectedTo(elasticsearchHostPort); + String proxy = System.getenv("DATAES_ELASTICSEARCH_PROXY"); + + if (proxy != null) { + configurationBuilder = configurationBuilder.withProxy(proxy); + } + if (clusterConnectionInfo.isUseSsl()) { configurationBuilder = ((ClientConfiguration.MaybeSecureClientConfigurationBuilder) configurationBuilder) .usingSsl();