Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 51fb872bea | |||
| 67c570606a | |||
| eb311d089f | |||
| 93492f86da | |||
| 88b2fa970d | |||
| 11e4ebf12c | |||
| 1272fdc188 | |||
| 96eac3ba73 | |||
| c47d284e6b | |||
| f5d651b497 | |||
| d35d38f7d5 | |||
| 2883280b00 | |||
| fedd97624e | |||
| 9fab24d5ef | |||
| bf32581105 | |||
| 7f89d79b12 | |||
| 955eb77add | |||
| 0086d35e54 | |||
| 53f0e79990 | |||
| 3da9eaadc5 | |||
| 310f6f0f22 |
@@ -9,7 +9,7 @@ image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-elasticsearch%2
|
||||
Since this pipeline is purely Docker-based, it's easy to:
|
||||
|
||||
* Debug what went wrong on your local machine.
|
||||
* Test out a a tweak to your `test.sh` script before sending it out.
|
||||
* Test out a a tweak to your `verify.sh` script before sending it out.
|
||||
* Experiment against a new image before submitting your pull request.
|
||||
|
||||
All of these use cases are great reasons to essentially run what the CI server does on your local machine.
|
||||
|
||||
Vendored
+73
-44
@@ -20,17 +20,24 @@ pipeline {
|
||||
}
|
||||
}
|
||||
agent {
|
||||
docker {
|
||||
image 'adoptopenjdk/openjdk8:latest'
|
||||
label 'data'
|
||||
args '-u root -v /var/run/docker.sock:/var/run/docker.sock -v $HOME:/tmp/jenkins-home'
|
||||
}
|
||||
label 'data'
|
||||
}
|
||||
options { timeout(time: 30, unit: 'MINUTES') }
|
||||
|
||||
environment {
|
||||
DOCKER_HUB = credentials('hub.docker.com-springbuildmaster')
|
||||
}
|
||||
|
||||
steps {
|
||||
sh 'mkdir -p /tmp/jenkins-home'
|
||||
sh 'chown -R 1001:1001 .'
|
||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw clean dependency:list verify -Dsort -U -B -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch'
|
||||
script {
|
||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
||||
docker.image('adoptopenjdk/openjdk8:latest').inside('-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home') {
|
||||
sh "docker login --username ${DOCKER_HUB_USR} --password ${DOCKER_HUB_PSW}"
|
||||
sh 'PROFILE=none ci/verify.sh'
|
||||
sh "ci/clean.sh"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,29 +51,47 @@ pipeline {
|
||||
parallel {
|
||||
stage("test: baseline (jdk11)") {
|
||||
agent {
|
||||
docker {
|
||||
image 'adoptopenjdk/openjdk11:latest'
|
||||
label 'data'
|
||||
args '-u root -v /var/run/docker.sock:/var/run/docker.sock -v $HOME:/tmp/jenkins-home'
|
||||
}
|
||||
label 'data'
|
||||
}
|
||||
options { timeout(time: 30, unit: 'MINUTES') }
|
||||
|
||||
environment {
|
||||
DOCKER_HUB = credentials('hub.docker.com-springbuildmaster')
|
||||
}
|
||||
|
||||
steps {
|
||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pjava11 clean dependency:list verify -Dsort -U -B -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch'
|
||||
script {
|
||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
||||
docker.image('adoptopenjdk/openjdk11:latest').inside('-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home') {
|
||||
sh "docker login --username ${DOCKER_HUB_USR} --password ${DOCKER_HUB_PSW}"
|
||||
sh 'PROFILE=java11 ci/verify.sh'
|
||||
sh "ci/clean.sh"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage("test: baseline (jdk15)") {
|
||||
agent {
|
||||
docker {
|
||||
image 'adoptopenjdk/openjdk15:latest'
|
||||
label 'data'
|
||||
args '-u root -v /var/run/docker.sock:/var/run/docker.sock -v $HOME:/tmp/jenkins-home'
|
||||
}
|
||||
label 'data'
|
||||
}
|
||||
options { timeout(time: 30, unit: 'MINUTES') }
|
||||
|
||||
environment {
|
||||
DOCKER_HUB = credentials('hub.docker.com-springbuildmaster')
|
||||
}
|
||||
|
||||
steps {
|
||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pjava11 clean dependency:list verify -Dsort -U -B -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch'
|
||||
script {
|
||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
||||
docker.image('adoptopenjdk/openjdk15:latest').inside('-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home') {
|
||||
sh "docker login --username ${DOCKER_HUB_USR} --password ${DOCKER_HUB_PSW}"
|
||||
sh 'PROFILE=java11 ci/verify.sh'
|
||||
sh "ci/clean.sh"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,11 +105,7 @@ pipeline {
|
||||
}
|
||||
}
|
||||
agent {
|
||||
docker {
|
||||
image 'adoptopenjdk/openjdk8:latest'
|
||||
label 'data'
|
||||
args '-u root -v /var/run/docker.sock:/var/run/docker.sock -v $HOME:/tmp/jenkins-home'
|
||||
}
|
||||
label 'data'
|
||||
}
|
||||
options { timeout(time: 20, unit: 'MINUTES') }
|
||||
|
||||
@@ -93,14 +114,20 @@ pipeline {
|
||||
}
|
||||
|
||||
steps {
|
||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pci,artifactory -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch ' +
|
||||
'-Dartifactory.server=https://repo.spring.io ' +
|
||||
"-Dartifactory.username=${ARTIFACTORY_USR} " +
|
||||
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
|
||||
"-Dartifactory.staging-repository=libs-snapshot-local " +
|
||||
"-Dartifactory.build-name=spring-data-elasticsearch " +
|
||||
"-Dartifactory.build-number=${BUILD_NUMBER} " +
|
||||
'-Dmaven.test.skip=true clean deploy -U -B'
|
||||
script {
|
||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
||||
docker.image('adoptopenjdk/openjdk8:latest').inside('-v $HOME:/tmp/jenkins-home') {
|
||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pci,artifactory -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch-non-root ' +
|
||||
'-Dartifactory.server=https://repo.spring.io ' +
|
||||
"-Dartifactory.username=${ARTIFACTORY_USR} " +
|
||||
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
|
||||
"-Dartifactory.staging-repository=libs-snapshot-local " +
|
||||
"-Dartifactory.build-name=spring-data-elasticsearch " +
|
||||
"-Dartifactory.build-number=${BUILD_NUMBER} " +
|
||||
'-Dmaven.test.skip=true clean deploy -U -B'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Publish documentation') {
|
||||
@@ -108,11 +135,7 @@ pipeline {
|
||||
branch '4.1.x'
|
||||
}
|
||||
agent {
|
||||
docker {
|
||||
image 'adoptopenjdk/openjdk8:latest'
|
||||
label 'data'
|
||||
args '-u root -v /var/run/docker.sock:/var/run/docker.sock -v $HOME:/tmp/jenkins-home'
|
||||
}
|
||||
label 'data'
|
||||
}
|
||||
options { timeout(time: 20, unit: 'MINUTES') }
|
||||
|
||||
@@ -121,12 +144,18 @@ pipeline {
|
||||
}
|
||||
|
||||
steps {
|
||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pci,distribute -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch ' +
|
||||
'-Dartifactory.server=https://repo.spring.io ' +
|
||||
"-Dartifactory.username=${ARTIFACTORY_USR} " +
|
||||
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
|
||||
"-Dartifactory.distribution-repository=temp-private-local " +
|
||||
'-Dmaven.test.skip=true clean deploy -U -B'
|
||||
script {
|
||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
||||
docker.image('adoptopenjdk/openjdk8:latest').inside('-v $HOME:/tmp/jenkins-home') {
|
||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pci,distribute -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch-non-root ' +
|
||||
'-Dartifactory.server=https://repo.spring.io ' +
|
||||
"-Dartifactory.username=${ARTIFACTORY_USR} " +
|
||||
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
|
||||
"-Dartifactory.distribution-repository=temp-private-local " +
|
||||
'-Dmaven.test.skip=true clean deploy -U -B'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash -x
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" \
|
||||
./mvnw clean -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash -x
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
mkdir -p /tmp/jenkins-home/.m2/spring-data-elasticsearch
|
||||
chown -R 1001:1001 .
|
||||
|
||||
MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" \
|
||||
./mvnw \
|
||||
-P${PROFILE} clean dependency:list verify -Dsort -U -B -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<version>4.1.4</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>2.4.2</version>
|
||||
<version>2.4.4</version>
|
||||
</parent>
|
||||
|
||||
<name>Spring Data Elasticsearch</name>
|
||||
@@ -22,8 +22,8 @@
|
||||
<elasticsearch>7.9.3</elasticsearch>
|
||||
<log4j>2.13.3</log4j>
|
||||
<netty>4.1.52.Final</netty>
|
||||
<springdata.commons>2.4.2</springdata.commons>
|
||||
<testcontainers>1.14.3</testcontainers>
|
||||
<springdata.commons>2.4.4</springdata.commons>
|
||||
<testcontainers>1.15.1</testcontainers>
|
||||
<java-module-name>spring.data.elasticsearch</java-module-name>
|
||||
</properties>
|
||||
|
||||
@@ -415,6 +415,11 @@
|
||||
<id>spring-plugins-release</id>
|
||||
<url>https://repo.spring.io/plugins-release</url>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>bintray-plugins</id>
|
||||
<name>bintray-plugins</name>
|
||||
<url>https://jcenter.bintray.com</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -154,7 +154,7 @@ httpHeaders.add("some-header", "on every request") <1>
|
||||
|
||||
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
|
||||
.connectedTo("localhost:9200", "localhost:9291") <2>
|
||||
.useSsl() <3>
|
||||
.usingSsl() <3>
|
||||
.withProxy("localhost:8888") <4>
|
||||
.withPathPrefix("ela") <5>
|
||||
.withConnectTimeout(Duration.ofSeconds(5)) <6>
|
||||
|
||||
+12
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2020 the original author or authors.
|
||||
* Copyright 2018-2021 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.
|
||||
@@ -27,6 +27,7 @@ import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.reactive.function.client.WebClient.Builder;
|
||||
import org.springframework.web.util.DefaultUriBuilderFactory;
|
||||
|
||||
/**
|
||||
* Default {@link WebClientProvider} that uses cached {@link WebClient} instances per {@code hostAndPort}.
|
||||
@@ -156,7 +157,16 @@ class DefaultWebClientProvider implements WebClientProvider {
|
||||
|
||||
String baseUrl = String.format("%s://%s:%d%s", this.scheme, socketAddress.getHostString(), socketAddress.getPort(),
|
||||
pathPrefix == null ? "" : '/' + pathPrefix);
|
||||
WebClient webClient = builder.baseUrl(baseUrl).filter((request, next) -> next.exchange(request).doOnError(errorListener)).build();
|
||||
|
||||
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(baseUrl);
|
||||
// the template will already be encoded by the RequestConverters methods
|
||||
uriBuilderFactory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY);
|
||||
builder.uriBuilderFactory(uriBuilderFactory); //
|
||||
|
||||
WebClient webClient = builder //
|
||||
.filter((request, next) -> next.exchange(request) //
|
||||
.doOnError(errorListener)) //
|
||||
.build(); //
|
||||
return webClientConfigurer.apply(webClient);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 the original author or authors.
|
||||
* Copyright 2019-2021 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.
|
||||
@@ -54,6 +54,7 @@ import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchRequestBuilder;
|
||||
import org.elasticsearch.action.support.ActiveShardCount;
|
||||
import org.elasticsearch.action.support.WriteRequest;
|
||||
import org.elasticsearch.action.update.UpdateRequest;
|
||||
import org.elasticsearch.action.update.UpdateRequestBuilder;
|
||||
import org.elasticsearch.client.Client;
|
||||
@@ -85,6 +86,7 @@ import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.script.ScriptType;
|
||||
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
|
||||
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
|
||||
import org.elasticsearch.search.sort.FieldSortBuilder;
|
||||
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
|
||||
@@ -860,9 +862,7 @@ class RequestFactory {
|
||||
elasticsearchConverter.updateQuery(searchQuery, clazz);
|
||||
List<MultiGetRequest.Item> items = new ArrayList<>();
|
||||
|
||||
if (!isEmpty(searchQuery.getFields())) {
|
||||
searchQuery.addSourceFilter(new FetchSourceFilter(toArray(searchQuery.getFields()), null));
|
||||
}
|
||||
FetchSourceContext fetchSourceContext = getFetchSourceContext(searchQuery);
|
||||
|
||||
if (!isEmpty(searchQuery.getIds())) {
|
||||
String indexName = index.getIndexName();
|
||||
@@ -872,6 +872,11 @@ class RequestFactory {
|
||||
if (searchQuery.getRoute() != null) {
|
||||
item = item.routing(searchQuery.getRoute());
|
||||
}
|
||||
|
||||
if (fetchSourceContext != null) {
|
||||
item.fetchSourceContext(fetchSourceContext);
|
||||
}
|
||||
|
||||
items.add(item);
|
||||
}
|
||||
}
|
||||
@@ -1553,38 +1558,6 @@ class RequestFactory {
|
||||
return elasticsearchFilter;
|
||||
}
|
||||
|
||||
// region response stuff
|
||||
|
||||
/**
|
||||
* extract the index settings information for a given index
|
||||
*
|
||||
* @param response the Elasticsearch response
|
||||
* @param indexName the index name
|
||||
* @return settings as {@link Document}
|
||||
*/
|
||||
public Document fromSettingsResponse(GetSettingsResponse response, String indexName) {
|
||||
|
||||
Document settings = Document.create();
|
||||
|
||||
if (!response.getIndexToDefaultSettings().isEmpty()) {
|
||||
Settings defaultSettings = response.getIndexToDefaultSettings().get(indexName);
|
||||
for (String key : defaultSettings.keySet()) {
|
||||
settings.put(key, defaultSettings.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
if (!response.getIndexToSettings().isEmpty()) {
|
||||
Settings customSettings = response.getIndexToSettings().get(indexName);
|
||||
for (String key : customSettings.keySet()) {
|
||||
settings.put(key, customSettings.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region helper functions
|
||||
@Nullable
|
||||
private ElasticsearchPersistentEntity<?> getPersistentEntity(@Nullable Class<?> clazz) {
|
||||
return clazz != null ? elasticsearchConverter.getMappingContext().getPersistentEntity(clazz) : null;
|
||||
@@ -1633,6 +1606,57 @@ class RequestFactory {
|
||||
return entity.hasSeqNoPrimaryTermProperty();
|
||||
}
|
||||
|
||||
private FetchSourceContext getFetchSourceContext(Query searchQuery) {
|
||||
FetchSourceContext fetchSourceContext = null;
|
||||
SourceFilter sourceFilter = searchQuery.getSourceFilter();
|
||||
|
||||
if (!isEmpty(searchQuery.getFields())) {
|
||||
if (sourceFilter == null) {
|
||||
sourceFilter = new FetchSourceFilter(toArray(searchQuery.getFields()), null);
|
||||
} else {
|
||||
ArrayList<String> arrayList = new ArrayList<>();
|
||||
Collections.addAll(arrayList, sourceFilter.getIncludes());
|
||||
sourceFilter = new FetchSourceFilter(toArray(arrayList), null);
|
||||
}
|
||||
|
||||
fetchSourceContext = new FetchSourceContext(true, sourceFilter.getIncludes(), sourceFilter.getExcludes());
|
||||
} else if (sourceFilter != null) {
|
||||
fetchSourceContext = new FetchSourceContext(true, sourceFilter.getIncludes(), sourceFilter.getExcludes());
|
||||
}
|
||||
return fetchSourceContext;
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region response stuff
|
||||
|
||||
/**
|
||||
* extract the index settings information for a given index
|
||||
*
|
||||
* @param response the Elasticsearch response
|
||||
* @param indexName the index name
|
||||
* @return settings as {@link Document}
|
||||
*/
|
||||
public Document fromSettingsResponse(GetSettingsResponse response, String indexName) {
|
||||
|
||||
Document settings = Document.create();
|
||||
|
||||
if (!response.getIndexToDefaultSettings().isEmpty()) {
|
||||
Settings defaultSettings = response.getIndexToDefaultSettings().get(indexName);
|
||||
for (String key : defaultSettings.keySet()) {
|
||||
settings.put(key, defaultSettings.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
if (!response.getIndexToSettings().isEmpty()) {
|
||||
Settings customSettings = response.getIndexToSettings().get(indexName);
|
||||
for (String key : customSettings.keySet()) {
|
||||
settings.put(key, customSettings.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
||||
+16
-15
@@ -172,19 +172,19 @@ public class GeoConverters {
|
||||
String type = GeoConverters.getGeoJsonType(source);
|
||||
|
||||
switch (type) {
|
||||
case GeoJsonPoint.TYPE:
|
||||
case "point":
|
||||
return MapToGeoJsonPointConverter.INSTANCE.convert(source);
|
||||
case GeoJsonMultiPoint.TYPE:
|
||||
case "multipoint":
|
||||
return MapToGeoJsonMultiPointConverter.INSTANCE.convert(source);
|
||||
case GeoJsonLineString.TYPE:
|
||||
case "linestring":
|
||||
return MapToGeoJsonLineStringConverter.INSTANCE.convert(source);
|
||||
case GeoJsonMultiLineString.TYPE:
|
||||
case "multilinestring":
|
||||
return MapToGeoJsonMultiLineStringConverter.INSTANCE.convert(source);
|
||||
case GeoJsonPolygon.TYPE:
|
||||
case "polygon":
|
||||
return MapToGeoJsonPolygonConverter.INSTANCE.convert(source);
|
||||
case GeoJsonMultiPolygon.TYPE:
|
||||
case "multipolygon":
|
||||
return MapToGeoJsonMultiPolygonConverter.INSTANCE.convert(source);
|
||||
case GeoJsonGeometryCollection.TYPE:
|
||||
case "geometrycollection":
|
||||
return MapToGeoJsonGeometryCollectionConverter.INSTANCE.convert(source);
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown GeoJson type " + type);
|
||||
@@ -217,7 +217,7 @@ public class GeoConverters {
|
||||
public GeoJsonPoint convert(Map<String, Object> source) {
|
||||
|
||||
String type = GeoConverters.getGeoJsonType(source);
|
||||
Assert.isTrue(type.equals(GeoJsonPoint.TYPE), "does not contain a type 'Point'");
|
||||
Assert.isTrue(type.equalsIgnoreCase(GeoJsonPoint.TYPE), "does not contain a type 'Point'");
|
||||
|
||||
Object coordinates = source.get("coordinates");
|
||||
Assert.notNull(coordinates, "Document to convert does not contain coordinates");
|
||||
@@ -255,7 +255,7 @@ public class GeoConverters {
|
||||
public GeoJsonMultiPoint convert(Map<String, Object> source) {
|
||||
|
||||
String type = GeoConverters.getGeoJsonType(source);
|
||||
Assert.isTrue(type.equals(GeoJsonMultiPoint.TYPE), "does not contain a type 'MultiPoint'");
|
||||
Assert.isTrue(type.equalsIgnoreCase(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");
|
||||
@@ -290,7 +290,7 @@ public class GeoConverters {
|
||||
public GeoJsonLineString convert(Map<String, Object> source) {
|
||||
|
||||
String type = GeoConverters.getGeoJsonType(source);
|
||||
Assert.isTrue(type.equals(GeoJsonLineString.TYPE), "does not contain a type 'LineString'");
|
||||
Assert.isTrue(type.equalsIgnoreCase(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");
|
||||
@@ -322,7 +322,7 @@ public class GeoConverters {
|
||||
public GeoJsonMultiLineString convert(Map<String, Object> source) {
|
||||
|
||||
String type = GeoConverters.getGeoJsonType(source);
|
||||
Assert.isTrue(type.equals(GeoJsonMultiLineString.TYPE), "does not contain a type 'MultiLineString'");
|
||||
Assert.isTrue(type.equalsIgnoreCase(GeoJsonMultiLineString.TYPE), "does not contain a type 'MultiLineString'");
|
||||
List<GeoJsonLineString> lines = geoJsonLineStringsFromMap(source);
|
||||
return GeoJsonMultiLineString.of(lines);
|
||||
}
|
||||
@@ -350,7 +350,7 @@ public class GeoConverters {
|
||||
public GeoJsonPolygon convert(Map<String, Object> source) {
|
||||
|
||||
String type = GeoConverters.getGeoJsonType(source);
|
||||
Assert.isTrue(type.equals(GeoJsonPolygon.TYPE), "does not contain a type 'Polygon'");
|
||||
Assert.isTrue(type.equalsIgnoreCase(GeoJsonPolygon.TYPE), "does not contain a type 'Polygon'");
|
||||
List<GeoJsonLineString> lines = geoJsonLineStringsFromMap(source);
|
||||
Assert.isTrue(lines.size() > 0, "no linestrings defined in polygon");
|
||||
GeoJsonPolygon geoJsonPolygon = GeoJsonPolygon.of(lines.get(0));
|
||||
@@ -394,7 +394,7 @@ public class GeoConverters {
|
||||
public GeoJsonMultiPolygon convert(Map<String, Object> source) {
|
||||
|
||||
String type = GeoConverters.getGeoJsonType(source);
|
||||
Assert.isTrue(type.equals(GeoJsonMultiPolygon.TYPE), "does not contain a type 'MultiPolygon'");
|
||||
Assert.isTrue(type.equalsIgnoreCase(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");
|
||||
@@ -441,7 +441,8 @@ public class GeoConverters {
|
||||
public GeoJsonGeometryCollection convert(Map<String, Object> source) {
|
||||
|
||||
String type = GeoConverters.getGeoJsonType(source);
|
||||
Assert.isTrue(type.equals(GeoJsonGeometryCollection.TYPE), "does not contain a type 'GeometryCollection'");
|
||||
Assert.isTrue(type.equalsIgnoreCase(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");
|
||||
@@ -461,7 +462,7 @@ public class GeoConverters {
|
||||
Assert.notNull(type, "Document to convert does not contain a type");
|
||||
Assert.isTrue(type instanceof String, "type must be a String");
|
||||
|
||||
return type.toString();
|
||||
return type.toString().toLowerCase();
|
||||
}
|
||||
|
||||
private static List<Double> toCoordinates(Point point) {
|
||||
|
||||
+5
@@ -31,6 +31,11 @@ import org.springframework.data.util.TypeInformation;
|
||||
public class SimpleElasticsearchMappingContext
|
||||
extends AbstractMappingContext<SimpleElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> {
|
||||
|
||||
@Override
|
||||
protected boolean shouldCreatePersistentEntityFor(TypeInformation<?> type) {
|
||||
return !ElasticsearchSimpleTypes.HOLDER.isSimpleType(type.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> SimpleElasticsearchPersistentEntity<?> createPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
return new SimpleElasticsearchPersistentEntity<>(typeInformation);
|
||||
|
||||
@@ -1,6 +1,51 @@
|
||||
Spring Data Elasticsearch Changelog
|
||||
===================================
|
||||
|
||||
Changes in version 4.1.4 (2021-02-17)
|
||||
-------------------------------------
|
||||
* #1667 - Couldn't find PersistentEntity for type class com.example.demo.dto.Address.
|
||||
* #1665 - ReactiveElasticsearchOperations indexName twice endcoding.
|
||||
* #1662 - Documentation fix.
|
||||
* #1659 - Fix source filter setup in multiget requests.
|
||||
* #1655 - GeoJson types can be lowercase in Elasticsearch.
|
||||
|
||||
|
||||
Changes in version 4.0.7.RELEASE (2021-02-17)
|
||||
---------------------------------------------
|
||||
* DATAES-996 - Update CI jobs with Docker Login.
|
||||
* #1667 - Couldn't find PersistentEntity for type class com.example.demo.dto.Address.
|
||||
* #1665 - ReactiveElasticsearchOperations indexName twice endcoding.
|
||||
* #1662 - Documentation fix.
|
||||
* #1659 - Fix source filter setup in multiget requests.
|
||||
|
||||
|
||||
Changes in version 3.2.13.RELEASE (2021-02-17)
|
||||
----------------------------------------------
|
||||
* #1694 - Upgrade to Elasticsearch 6.8.14.
|
||||
* #1662 - Documentation fix.
|
||||
|
||||
|
||||
Changes in version 4.2.0-M2 (2021-01-13)
|
||||
----------------------------------------
|
||||
* DATAES-1003 - add timeout to search query.
|
||||
* DATAES-996 - Update CI jobs with Docker Login.
|
||||
* DATAES-982 - Improve refresh handling.
|
||||
* DATAES-946 - Support 'wildcard' field type.
|
||||
* #1640 - Add support for GetFieldMapping request in ReactiveElasticsearchClient.
|
||||
* #1638 - Upgrade to Elasticsearch 7.10.1.
|
||||
* #1634 - Update Testcontainers dependency.
|
||||
* #1632 - Update copyright notice to 2021.
|
||||
* #1629 - Update repository after GitHub issues migration.
|
||||
* #1576 - Add version of Spring dependency to docs [DATAES-1004].
|
||||
* #1056 - Repository initialization should throw an Exception when index cannot be created [DATAES-481].
|
||||
|
||||
|
||||
Changes in version 4.1.3 (2021-01-13)
|
||||
-------------------------------------
|
||||
* DATAES-996 - Update CI jobs with Docker Login.
|
||||
* #1634 - Update Testcontainers dependency.
|
||||
|
||||
|
||||
Changes in version 4.1.2 (2020-12-09)
|
||||
-------------------------------------
|
||||
* DATAES-991 - Wrong value for TermVector(with_positions_offets_payloads).
|
||||
@@ -1437,6 +1482,11 @@ Release Notes - Spring Data Elasticsearch - Version 1.0 M1 (2014-02-07)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data Elasticsearch 4.1.2 (2020.0.2)
|
||||
Spring Data Elasticsearch 4.1.4 (2020.0.4)
|
||||
Copyright (c) [2013-2019] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
@@ -22,3 +22,5 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+29
@@ -32,6 +32,8 @@ import java.lang.Boolean;
|
||||
import java.lang.Long;
|
||||
import java.lang.Object;
|
||||
import java.net.ConnectException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -1037,6 +1039,32 @@ public class ReactiveElasticsearchTemplateIntegrationTests {
|
||||
assertThat(searchHits.getSearchHits().size()).isEqualTo(5);
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Test // #1665
|
||||
@DisplayName("should be able to process date-math-index names")
|
||||
void shouldBeAbleToProcessDateMathIndexNames() {
|
||||
|
||||
String indexName = "foo-" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy.MM"));
|
||||
String dateMathIndexName = "<foo-{now/M{yyyy.MM}}>";
|
||||
|
||||
template.indexOps(IndexCoordinates.of(dateMathIndexName)) //
|
||||
.create() //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(true) //
|
||||
.verifyComplete(); //
|
||||
|
||||
template.indexOps(IndexCoordinates.of(indexName)) //
|
||||
.exists() //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(true) //
|
||||
.verifyComplete(); //
|
||||
|
||||
template.indexOps(IndexCoordinates.of(dateMathIndexName)) //
|
||||
.delete() //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(true) //
|
||||
.verifyComplete(); //
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Helper functions
|
||||
@@ -1134,5 +1162,6 @@ public class ReactiveElasticsearchTemplateIntegrationTests {
|
||||
@Id private String id;
|
||||
@Version private Long version;
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright 2021 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;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
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.annotation.Id;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.elasticsearch.core.query.SourceFilter;
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
*/
|
||||
@SpringIntegrationTest
|
||||
@ContextConfiguration(classes = { ElasticsearchRestTemplateConfiguration.class })
|
||||
public class SourceFilterIntegrationTests {
|
||||
|
||||
@Autowired private ElasticsearchOperations operations;
|
||||
private IndexOperations indexOps;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
indexOps = operations.indexOps(Entity.class);
|
||||
indexOps.create();
|
||||
indexOps.putMapping();
|
||||
|
||||
operations.save(Entity.builder().id("42").field1("one").field2("two").field3("three").build());
|
||||
indexOps.refresh();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
indexOps.delete();
|
||||
}
|
||||
|
||||
@Test // #1659
|
||||
@DisplayName("should only return requested fields on search")
|
||||
void shouldOnlyReturnRequestedFieldsOnSearch() {
|
||||
|
||||
Query query = Query.findAll();
|
||||
query.addFields("field2");
|
||||
|
||||
SearchHits<Entity> searchHits = operations.search(query, Entity.class);
|
||||
|
||||
assertThat(searchHits).hasSize(1);
|
||||
Entity entity = searchHits.getSearchHit(0).getContent();
|
||||
assertThat(entity.getField1()).isNull();
|
||||
assertThat(entity.getField2()).isEqualTo("two");
|
||||
assertThat(entity.getField3()).isNull();
|
||||
}
|
||||
|
||||
@Test // #1659
|
||||
@DisplayName("should only return requested fields on multiget")
|
||||
void shouldOnlyReturnRequestedFieldsOnGMultiGet() {
|
||||
|
||||
Query query = new NativeSearchQueryBuilder().withIds(Collections.singleton("42")).build();
|
||||
query.addFields("field2");
|
||||
|
||||
List<Entity> entities = operations.multiGet(query, Entity.class);
|
||||
|
||||
assertThat(entities).hasSize(1);
|
||||
Entity entity = entities.get(0);
|
||||
assertThat(entity.getField1()).isNull();
|
||||
assertThat(entity.getField2()).isEqualTo("two");
|
||||
assertThat(entity.getField3()).isNull();
|
||||
}
|
||||
|
||||
@Test // #1659
|
||||
@DisplayName("should not return excluded fields from SourceFilter on search")
|
||||
void shouldNotReturnExcludedFieldsFromSourceFilterOnSearch() {
|
||||
|
||||
Query query = Query.findAll();
|
||||
query.addSourceFilter(new SourceFilter() {
|
||||
@Override
|
||||
public String[] getIncludes() {
|
||||
return new String[] {};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getExcludes() {
|
||||
return new String[] { "field2" };
|
||||
}
|
||||
});
|
||||
|
||||
SearchHits<Entity> entities = operations.search(query, Entity.class);
|
||||
|
||||
assertThat(entities).hasSize(1);
|
||||
Entity entity = entities.getSearchHit(0).getContent();
|
||||
assertThat(entity.getField1()).isNotNull();
|
||||
assertThat(entity.getField2()).isNull();
|
||||
assertThat(entity.getField3()).isNotNull();
|
||||
}
|
||||
|
||||
@Test // #1659
|
||||
@DisplayName("should not return excluded fields from SourceFilter on multiget")
|
||||
void shouldNotReturnExcludedFieldsFromSourceFilterOnMultiGet() {
|
||||
|
||||
Query query = new NativeSearchQueryBuilder().withIds(Collections.singleton("42")).build();
|
||||
query.addSourceFilter(new SourceFilter() {
|
||||
@Override
|
||||
public String[] getIncludes() {
|
||||
return new String[] {};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getExcludes() {
|
||||
return new String[] { "field2" };
|
||||
}
|
||||
});
|
||||
|
||||
List<Entity> entities = operations.multiGet(query, Entity.class);
|
||||
|
||||
assertThat(entities).hasSize(1);
|
||||
Entity entity = entities.get(0);
|
||||
assertThat(entity.getField1()).isNotNull();
|
||||
assertThat(entity.getField2()).isNull();
|
||||
assertThat(entity.getField3()).isNotNull();
|
||||
}
|
||||
|
||||
@Test // #1659
|
||||
@DisplayName("should only return included fields from SourceFilter on search")
|
||||
void shouldOnlyReturnIncludedFieldsFromSourceFilterOnSearch() {
|
||||
|
||||
Query query = Query.findAll();
|
||||
query.addSourceFilter(new SourceFilter() {
|
||||
@Override
|
||||
public String[] getIncludes() {
|
||||
return new String[] { "field2" };
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getExcludes() {
|
||||
return new String[] {};
|
||||
}
|
||||
});
|
||||
|
||||
SearchHits<Entity> entities = operations.search(query, Entity.class);
|
||||
|
||||
assertThat(entities).hasSize(1);
|
||||
Entity entity = entities.getSearchHit(0).getContent();
|
||||
assertThat(entity.getField1()).isNull();
|
||||
assertThat(entity.getField2()).isNotNull();
|
||||
assertThat(entity.getField3()).isNull();
|
||||
}
|
||||
|
||||
@Test // #1659
|
||||
@DisplayName("should only return included fields from SourceFilter on multiget")
|
||||
void shouldOnlyReturnIncludedFieldsFromSourceFilterOnMultiGet() {
|
||||
|
||||
Query query = new NativeSearchQueryBuilder().withIds(Collections.singleton("42")).build();
|
||||
query.addSourceFilter(new SourceFilter() {
|
||||
@Override
|
||||
public String[] getIncludes() {
|
||||
return new String[] { "field2" };
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getExcludes() {
|
||||
return new String[] {};
|
||||
}
|
||||
});
|
||||
|
||||
List<Entity> entities = operations.multiGet(query, Entity.class);
|
||||
|
||||
assertThat(entities).hasSize(1);
|
||||
Entity entity = entities.get(0);
|
||||
assertThat(entity.getField1()).isNull();
|
||||
assertThat(entity.getField2()).isNotNull();
|
||||
assertThat(entity.getField3()).isNull();
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Document(indexName = "sourcefilter-tests")
|
||||
public static class Entity {
|
||||
@Id private String id;
|
||||
@Field(type = FieldType.Text) private String field1;
|
||||
@Field(type = FieldType.Text) private String field2;
|
||||
@Field(type = FieldType.Text) private String field3;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2021 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;
|
||||
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
*/
|
||||
@ContextConfiguration(classes = { ElasticsearchTemplateConfiguration.class })
|
||||
public class SourceFilterIntegrationTransportTests extends SourceFilterIntegrationTests {}
|
||||
+19
-10
@@ -53,6 +53,9 @@ class GeoConvertersUnitTests {
|
||||
@DisplayName("GeoJsonPoint")
|
||||
class GeoJsonPointUnitTests {
|
||||
|
||||
// NOTE: the test converting from a map contains the type names in lowercase, that might be returned from
|
||||
// Elasticsearch
|
||||
|
||||
@Test // DATAES-930
|
||||
@DisplayName("should be converted to a Map")
|
||||
void shouldBeConvertedToAMap() throws JSONException {
|
||||
@@ -75,7 +78,7 @@ class GeoConvertersUnitTests {
|
||||
|
||||
// make sure we can read int values as well
|
||||
String json = "{\n" + //
|
||||
" \"type\": \"Point\",\n" + //
|
||||
" \"type\": \"point\",\n" + //
|
||||
" \"coordinates\": [12, 34.0]\n" + //
|
||||
"}"; //
|
||||
|
||||
@@ -117,8 +120,14 @@ class GeoConvertersUnitTests {
|
||||
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";
|
||||
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));
|
||||
@@ -158,7 +167,7 @@ class GeoConvertersUnitTests {
|
||||
|
||||
// make sure we can read int values as well
|
||||
String json = "{\n" + //
|
||||
" \"type\": \"LineString\",\n" + //
|
||||
" \"type\": \"linestring\",\n" + //
|
||||
" \"coordinates\": [\n" + //
|
||||
" [12.0, 34],\n" + //
|
||||
" [56, 78.0]\n" //
|
||||
@@ -205,7 +214,7 @@ class GeoConvertersUnitTests {
|
||||
void shouldBeConvertedFromAMap() {
|
||||
// make sure we can read int values as well
|
||||
String json = "{\n" + //
|
||||
" \"type\": \"MultiLineString\",\n" + //
|
||||
" \"type\": \"multilinestring\",\n" + //
|
||||
" \"coordinates\": [\n" + //
|
||||
" [[12, 34.0], [56.0, 78]],\n" + //
|
||||
" [[90.0, 12], [34, 56.0]]\n" + //
|
||||
@@ -256,7 +265,7 @@ class GeoConvertersUnitTests {
|
||||
void shouldBeConvertedFromAMap() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"type\": \"Polygon\",\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" + //
|
||||
@@ -308,7 +317,7 @@ class GeoConvertersUnitTests {
|
||||
void shouldBeConvertedFromAMap() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"type\": \"MultiPolygon\",\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" + //
|
||||
@@ -369,14 +378,14 @@ class GeoConvertersUnitTests {
|
||||
void shouldBeConvertedFromAMap() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"type\": \"GeometryCollection\",\n" + //
|
||||
" \"type\": \"geometrycollection\",\n" + //
|
||||
" \"geometries\": [\n" + //
|
||||
" {\n" + //
|
||||
" \"type\": \"Point\",\n" + //
|
||||
" \"type\": \"point\",\n" + //
|
||||
" \"coordinates\": [12.0, 34.0]\n" + //
|
||||
" },\n" + //
|
||||
" {\n" + //
|
||||
" \"type\": \"Polygon\",\n" + //
|
||||
" \"type\": \"polygon\",\n" + //
|
||||
" \"coordinates\": [\n" + //
|
||||
" [[12.0, 34.0], [56.0, 78.0], [90.0, 12.0], [12.0, 34.0]]\n" + //
|
||||
" ]\n" + //
|
||||
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2021 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.mapping;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
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.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.convert.ReadingConverter;
|
||||
import org.springframework.data.convert.WritingConverter;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.IndexOperations;
|
||||
import org.springframework.data.elasticsearch.core.SearchHits;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoJsonPoint;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
||||
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* Test that a whole entity can be converted using custom conversions
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
*/
|
||||
@SpringIntegrationTest
|
||||
@ContextConfiguration(classes = { EntityCustomConversionIntegrationTests.Config.class })
|
||||
public class EntityCustomConversionIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@EnableElasticsearchRepositories(basePackages = { "org.springframework.data.elasticsearch.core.mapping" },
|
||||
considerNestedRepositories = true)
|
||||
static class Config extends ElasticsearchRestTemplateConfiguration {
|
||||
@Override
|
||||
public ElasticsearchCustomConversions elasticsearchCustomConversions() {
|
||||
return new ElasticsearchCustomConversions(Arrays.asList(new EntityToMapConverter(), new MapToEntityConverter()));
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired private ElasticsearchOperations operations;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
IndexOperations indexOps = operations.indexOps(Entity.class);
|
||||
indexOps.create();
|
||||
indexOps.putMapping();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
operations.indexOps(Entity.class).delete();
|
||||
}
|
||||
|
||||
@Test // #1667
|
||||
@DisplayName("should use CustomConversions on entity")
|
||||
void shouldUseCustomConversionsOnEntity() {
|
||||
|
||||
Entity entity = Entity.builder() //
|
||||
.value("hello") //
|
||||
.location(GeoJsonPoint.of(8.0, 42.7)) //
|
||||
.build();
|
||||
|
||||
org.springframework.data.elasticsearch.core.document.Document document = org.springframework.data.elasticsearch.core.document.Document
|
||||
.create();
|
||||
operations.getElasticsearchConverter().write(entity, document);
|
||||
|
||||
assertThat(document.getString("the_value")).isEqualTo("hello");
|
||||
assertThat(document.getString("the_lon")).isEqualTo("8.0");
|
||||
assertThat(document.getString("the_lat")).isEqualTo("42.7");
|
||||
}
|
||||
|
||||
@Test // #1667
|
||||
@DisplayName("should store and load entity from Elasticsearch")
|
||||
void shouldStoreAndLoadEntityFromElasticsearch() {
|
||||
|
||||
Entity entity = Entity.builder() //
|
||||
.value("hello") //
|
||||
.location(GeoJsonPoint.of(8.0, 42.7)) //
|
||||
.build();
|
||||
|
||||
Entity savedEntity = operations.save(entity);
|
||||
operations.indexOps(Entity.class).refresh();
|
||||
|
||||
SearchHits<Entity> searchHits = operations.search(Query.findAll(), Entity.class);
|
||||
assertThat(searchHits.getTotalHits()).isEqualTo(1);
|
||||
Entity foundEntity = searchHits.getSearchHit(0).getContent();
|
||||
assertThat(foundEntity).isEqualTo(entity);
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Document(indexName = "entity-with-custom-conversions")
|
||||
static class Entity {
|
||||
private String value;
|
||||
private GeoJsonPoint location;
|
||||
}
|
||||
|
||||
@WritingConverter
|
||||
static class EntityToMapConverter implements Converter<Entity, Map<String, Object>> {
|
||||
@Override
|
||||
public Map<String, Object> convert(Entity source) {
|
||||
LinkedHashMap<String, Object> target = new LinkedHashMap<>();
|
||||
target.put("the_value", source.getValue());
|
||||
target.put("the_lat", "" + source.getLocation().getY());
|
||||
target.put("the_lon", "" + source.getLocation().getX());
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
@ReadingConverter
|
||||
static class MapToEntityConverter implements Converter<Map<String, Object>, Entity> {
|
||||
|
||||
@Override
|
||||
public Entity convert(Map<String, Object> source) {
|
||||
Entity entity = new Entity();
|
||||
entity.setValue((String) source.get("the_value"));
|
||||
entity.setLocation(GeoJsonPoint.of( //
|
||||
Double.parseDouble((String) (source.get("the_lon"))), //
|
||||
Double.parseDouble((String) (source.get("the_lat"))) //
|
||||
));
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user