1
0
mirror of synced 2026-05-23 12:43:17 +00:00

Compare commits

...

65 Commits

Author SHA1 Message Date
Mark Paluch c03c790d46 Release version 4.2.10 (2021.0.10).
See #2090
2022-03-21 14:26:38 +01:00
Mark Paluch 41d91237d7 Prepare 4.2.10 (2021.0.10).
See #2090
2022-03-21 14:26:10 +01:00
Mark Paluch fbcaeb10fd Use Java 8 to build snapshots for Artifactory.
Closes #2095
2022-03-15 14:20:06 +01:00
Mark Paluch 457a6e778e Update CI properties.
See #2090
2022-02-22 14:08:49 +01:00
Mark Paluch 16f66e4c17 Upgrade to Maven Wrapper 3.8.4.
See #2099
2022-02-22 13:55:13 +01:00
Mark Paluch bca4ba3fab Polishing.
Fix Javadoc errors.

See #2095
2022-02-22 09:56:31 +01:00
Mark Paluch 88924903e8 Polishing.
Fix Javadoc errors.

See #2095
2022-02-22 09:40:28 +01:00
Mark Paluch 7192d29095 Use Java 17 to build snapshots for Artifactory.
Closes #2095
2022-02-22 09:01:48 +01:00
Mark Paluch e0ca73b9b1 Update CI properties.
See #2090
2022-02-21 14:51:45 +01:00
Peter-Josef Meisch 8285dd0cd0 Documentation about compatibility headers.
Original Pull Request #2093
Closes #2088

(cherry picked from commit cf380e289d)
2022-02-18 20:53:42 +01:00
Mark Paluch 6f73ac952b After release cleanups.
See #2055
2022-02-18 10:32:53 +01:00
Mark Paluch 336b290e18 Prepare next development iteration.
See #2055
2022-02-18 10:32:51 +01:00
Mark Paluch e0286aa59a Release version 4.2.9 (2021.0.9).
See #2055
2022-02-18 10:24:49 +01:00
Mark Paluch 247be2b002 Prepare 4.2.9 (2021.0.9).
See #2055
2022-02-18 10:24:15 +01:00
Greg L. Turnquist e2ac3194b0 Update CI properties.
See #2055
2022-02-14 14:38:48 -06:00
Mark Paluch 0c81b4b368 Polishing.
Extract Docker and Artifactory credentials into properties file.

See #2074
2022-02-04 15:20:42 +01:00
Greg L. Turnquist 5fd35cb4c7 Externalize build properties.
See #2074.
2022-02-04 15:20:21 +01:00
Christoph Strobl af31cce875 After release cleanups.
See #1988
2022-01-14 10:00:58 +01:00
Christoph Strobl 23126ff3da Prepare next development iteration.
See #1988
2022-01-14 10:00:55 +01:00
Christoph Strobl 0b3ecf6b23 Release version 4.2.8 (2021.0.8).
See #1988
2022-01-14 09:47:50 +01:00
Christoph Strobl b96b5c2322 Prepare 4.2.8 (2021.0.8).
See #1988
2022-01-14 09:47:09 +01:00
Peter-Josef Meisch 2a646e583d Update to log4j 2.17.0 2021-12-18 20:35:27 +01:00
Peter-Josef Meisch 09c76b4694 update log4j dependency version 2021-12-14 13:51:02 +01:00
Peter-Josef Meisch 1b59b31a72 Fix FieldType mapping.
Original PullRequest #2026
Closes #2024

(cherry picked from commit f7a6a97c4e)
(cherry picked from commit f3f9ca4002)
2021-12-14 06:27:03 +01:00
Sascha Woo 2aba7a57fb Fix IndexOutOfBoundsException when try to map inner hits with no results returned.
Original Pull Request #1998
Closes #1997

(cherry picked from commit 49324a3)
2021-11-24 10:39:54 +01:00
Peter-Josef Meisch 15ca49a92e Exclude commons-logging dependency from Elasticsearch dependencies.
Original Pull Request #1993
Closes #1989

(cherry picked from commit 95401a5bd7)
2021-11-13 14:58:00 +01:00
Jens Schauder b7088f8002 After release cleanups.
See #1964
2021-11-12 10:38:58 +01:00
Jens Schauder 76f7ed5196 Prepare next development iteration.
See #1964
2021-11-12 10:38:55 +01:00
Jens Schauder e5445cf56f Release version 4.2.7 (2021.0.7).
See #1964
2021-11-12 10:27:21 +01:00
Jens Schauder 09a4e59e8d Prepare 4.2.7 (2021.0.7).
See #1964
2021-11-12 10:26:44 +01:00
Peter-Josef Meisch 1e33e0f498 fix import after cherrypick 2021-10-26 21:45:02 +02:00
Anton Naydenov e4df537382 Added RefreshPolicy setter to the AbstractElasticsearchTemplate copy method.
Original Pull Request #1976
Closes #1978

(cherry picked from commit 8894dd3d21)
2021-10-26 19:18:23 +02:00
jongchan lee c1ab4d66e0 Add scrolltime condition when using SearchRequest.
Original Pull Request #1975
Closes #1974

(cherry picked from commit f1b4a54bc2)
2021-10-26 18:49:24 +02:00
Mark Paluch 42cbab7ef6 After release cleanups.
See #1936
2021-10-18 11:19:45 +02:00
Mark Paluch 9eed498fab Prepare next development iteration.
See #1936
2021-10-18 11:19:42 +02:00
Mark Paluch f16f70ff0f Release version 4.2.6 (2021.0.6).
See #1936
2021-10-18 11:11:46 +02:00
Mark Paluch 7494d344c5 Prepare 4.2.6 (2021.0.6).
See #1936
2021-10-18 11:10:49 +02:00
Mark Paluch ca61901c1c After release cleanups.
See #1898
2021-09-17 09:27:40 +02:00
Mark Paluch 323ccc9729 Prepare next development iteration.
See #1898
2021-09-17 09:27:36 +02:00
Mark Paluch d2960d764f Release version 4.2.5 (2021.0.5).
See #1898
2021-09-17 09:18:33 +02:00
Mark Paluch 8bb0a60450 Prepare 4.2.5 (2021.0.5).
See #1898
2021-09-17 09:17:30 +02:00
Christoph Strobl e33fe4d9fd Change visibility of PersistentEntitiesFactoryBean.
Closes: #1934
2021-09-16 08:08:41 +02:00
Mark Paluch 0fd1b96ef3 Upgrade to Maven Wrapper 3.8.2.
See #1927
2021-09-10 15:39:43 +02:00
Peter-Josef Meisch 30bc91c753 Polishing
(cherry picked from commit 6941e31ba4)
2021-09-10 08:31:51 +02:00
Nic Hines 92806d2e11 Change mapping of connectionRequestTimeout to ConnPool leaseTimeout.
Original Pull Request: #1925
Closes: #1926

(cherry picked from commit 3b8f0c9d56)
2021-09-10 08:31:51 +02:00
Peter-Josef Meisch 2dd0a6771f Fix @Query method implementation for unpaged queries.
Original Pull Request #1919
Closes #1917

(cherry picked from commit e71758686c)
2021-09-03 21:50:26 +02:00
Jens Schauder 79e0260f48 After release cleanups.
See #1875
2021-08-12 11:37:31 +02:00
Jens Schauder 8d79a3efcf Prepare next development iteration.
See #1875
2021-08-12 11:37:30 +02:00
Jens Schauder d785c6c33c Release version 4.2.4 (2021.0.4).
See #1875
2021-08-12 11:22:50 +02:00
Jens Schauder c89368ce42 Prepare 4.2.4 (2021.0.4).
See #1875
2021-08-12 11:22:27 +02:00
Peter-Josef Meisch c0781efbaa Fix NPE on IndexQuery with source and version.
Original Pull Request #1894
Closes #1893

(cherry picked from commit 36b449c385)
2021-08-06 22:39:41 +02:00
Peter-Josef Meisch d371404f90 Fix http URL in license header
(cherry picked from commit e6869bcdfd)
2021-07-22 07:32:58 +02:00
Peter-Josef Meisch cc5b4fa635 Upgrade maven wrapper to use maven 3.8.1.
Original Pull Request #1878
Closes #1877

(cherry picked from commit d2e3ea26b8)
2021-07-22 07:32:58 +02:00
Peter-Josef Meisch deae205fd4 Polishing.
(cherry picked from commit d3e8c9fce5)
2021-07-17 19:18:45 +02:00
Frnandu Martinski 796a5ebe34 Fix uri encode bug when url path start with '/'.
Original Pull Request #1873
Closes #1870

(cherry picked from commit d88fb037da)
2021-07-17 19:18:44 +02:00
Jens Schauder 2c63ba4097 After release cleanups.
See #1850
2021-07-16 11:51:06 +02:00
Jens Schauder fe255c1bdc Prepare next development iteration.
See #1850
2021-07-16 11:51:03 +02:00
Jens Schauder 6f89e17451 Release version 4.2.3 (2021.0.3).
See #1850
2021-07-16 11:35:23 +02:00
Jens Schauder 0ad4fcb2eb Prepare 4.2.3 (2021.0.3).
See #1850
2021-07-16 11:34:28 +02:00
Jens Schauder 4c3281f1eb Updated changelog.
See #1850
2021-07-16 11:34:25 +02:00
Peter-Josef Meisch 303438ae63 Use registered converters for parameters of @Query annotated methods.
Original Pull Request #1867
Closes #1866

(cherry picked from commit 27094724dc)
2021-07-14 20:02:44 +02:00
Niklas Herder 254948d1c9 Support collection parameters in @Query methods.
Original Pull Request #1856
Closes #1858

(cherry picked from commit 6f84a1c589)
2021-07-03 18:08:36 +02:00
Sascha Woo 0bb239a674 Add missing hashCode and equals methods to JoinField.
Original Pull Request #1847
Closes #1846

(cherry picked from commit a16a87f3fa)
2021-06-23 20:37:32 +02:00
Mark Paluch 3336ceade8 After release cleanups.
See #1814
2021-06-22 16:05:23 +02:00
Mark Paluch e7398df948 Prepare next development iteration.
See #1814
2021-06-22 16:05:20 +02:00
37 changed files with 1058 additions and 349 deletions
+117
View File
@@ -0,0 +1,117 @@
/*
* Copyright 2007-present 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.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
* use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH =
".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if(mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if(mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}
Vendored Executable → Regular
BIN
View File
Binary file not shown.
Vendored Executable → Regular
+3 -1
View File
@@ -1 +1,3 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip
#Tue Feb 22 13:55:13 CET 2022
wrapperUrl=https\://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip
Vendored
+26 -48
View File
@@ -1,3 +1,9 @@
def p = [:]
node {
checkout scm
p = readProperties interpolate: true, file: 'ci/pipeline.properties'
}
pipeline {
agent none
@@ -12,7 +18,7 @@ pipeline {
}
stages {
stage("test: baseline (jdk8)") {
stage("test: baseline (main)") {
when {
anyOf {
branch '4.2.x'
@@ -25,14 +31,14 @@ pipeline {
options { timeout(time: 30, unit: 'MINUTES') }
environment {
DOCKER_HUB = credentials('hub.docker.com-springbuildmaster')
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
DOCKER_HUB = credentials("${p['docker.credentials']}")
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
}
steps {
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') {
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.docker']) {
sh "docker login --username ${DOCKER_HUB_USR} --password ${DOCKER_HUB_PSW}"
sh 'PROFILE=none ci/verify.sh'
sh "ci/clean.sh"
@@ -50,23 +56,23 @@ pipeline {
}
}
parallel {
stage("test: baseline (jdk11)") {
stage("test: baseline (next)") {
agent {
label 'data'
}
options { timeout(time: 30, unit: 'MINUTES') }
environment {
DOCKER_HUB = credentials('hub.docker.com-springbuildmaster')
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
DOCKER_HUB = credentials("${p['docker.credentials']}")
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
}
steps {
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') {
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
docker.image(p['docker.java.11.image']).inside(p['docker.java.inside.docker']) {
sh "docker login --username ${DOCKER_HUB_USR} --password ${DOCKER_HUB_PSW}"
sh 'PROFILE=java11 ci/verify.sh'
sh 'PROFILE=none ci/verify.sh'
sh "ci/clean.sh"
}
}
@@ -74,23 +80,23 @@ pipeline {
}
}
stage("test: baseline (jdk16)") {
stage("test: baseline (LTS)") {
agent {
label 'data'
}
options { timeout(time: 30, unit: 'MINUTES') }
environment {
DOCKER_HUB = credentials('hub.docker.com-springbuildmaster')
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
DOCKER_HUB = credentials("${p['docker.credentials']}")
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
}
steps {
script {
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
docker.image('adoptopenjdk/openjdk16: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') {
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
docker.image(p['docker.java.lts.image']).inside(p['docker.java.inside.docker']) {
sh "docker login --username ${DOCKER_HUB_USR} --password ${DOCKER_HUB_PSW}"
sh 'PROFILE=java11 ci/verify.sh'
sh 'PROFILE=none ci/verify.sh'
sh "ci/clean.sh"
}
}
@@ -113,13 +119,13 @@ pipeline {
options { timeout(time: 20, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
}
steps {
script {
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
docker.image('adoptopenjdk/openjdk8:latest').inside('-v $HOME:/tmp/jenkins-home') {
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.basic']) {
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pci,artifactory -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch-non-root ' +
'-Dartifactory.server=https://repo.spring.io ' +
"-Dartifactory.username=${ARTIFACTORY_USR} " +
@@ -133,34 +139,6 @@ pipeline {
}
}
}
stage('Publish documentation') {
when {
branch '4.2.x'
}
agent {
label 'data'
}
options { timeout(time: 20, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
}
steps {
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 -s settings.xml -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'
}
}
}
}
}
}
post {
+31
View File
@@ -0,0 +1,31 @@
# Java versions
java.main.tag=8u322-b06-jdk
java.11.tag=11.0.14.1_1-jdk
java.15.tag=15.0.2_7-jdk-hotspot
java.lts.tag=17.0.2_8-jdk
# Docker container images - standard
docker.java.main.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.main.tag}
docker.java.11.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.11.tag}
docker.java.15.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/adoptopenjdk:${java.15.tag}
docker.java.lts.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.lts.tag}
# Supported versions of MongoDB
docker.mongodb.4.0.version=4.0.28
docker.mongodb.4.4.version=4.4.12
docker.mongodb.5.0.version=5.0.6
# Supported versions of Redis
docker.redis.6.version=6.2.6
# Supported versions of Cassandra
docker.cassandra.3.version=3.11.12
# Docker environment settings
docker.java.inside.basic=-v $HOME:/tmp/jenkins-home
docker.java.inside.docker=-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home
# Credentials
docker.registry=
docker.credentials=hub.docker.com-springbuildmaster
artifactory.credentials=02bd1690-b54f-4c9f-819d-a77cb7a9822c
Vendored
+30 -6
View File
@@ -8,7 +8,7 @@
# "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
# http://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
@@ -19,7 +19,7 @@
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
@@ -114,7 +114,6 @@ if $mingw ; then
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
# TODO classpath?
fi
if [ -z "$JAVA_HOME" ]; then
@@ -212,7 +211,11 @@ else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
@@ -221,22 +224,38 @@ else
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
wget "$jarUrl" -O "$wrapperJarPath"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
curl -o "$wrapperJarPath" "$jarUrl"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
@@ -277,6 +296,11 @@ if $cygwin; then
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
Vendored Executable → Regular
+33 -12
View File
@@ -7,7 +7,7 @@
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@@ -18,7 +18,7 @@
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@@ -26,7 +26,7 @@
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@@ -37,7 +37,7 @@
@echo off
@REM set title of command window
title %0
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
@@ -120,23 +120,44 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
echo Found %WRAPPER_JAR%
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
echo Finished downloading %WRAPPER_JAR%
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
+37 -23
View File
@@ -5,12 +5,12 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>4.2.2</version>
<version>4.2.10</version>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>2.5.2</version>
<version>2.5.10</version>
</parent>
<name>Spring Data Elasticsearch</name>
@@ -20,9 +20,9 @@
<properties>
<commonslang>2.6</commonslang>
<elasticsearch>7.12.1</elasticsearch>
<log4j>2.13.3</log4j>
<log4j>2.17.0</log4j>
<netty>4.1.52.Final</netty>
<springdata.commons>2.5.2</springdata.commons>
<springdata.commons>2.5.10</springdata.commons>
<testcontainers>1.15.1</testcontainers>
<java-module-name>spring.data.elasticsearch</java-module-name>
</properties>
@@ -152,6 +152,12 @@
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>${elasticsearch}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
@@ -159,6 +165,12 @@
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>transport-netty4-client</artifactId>
<version>${elasticsearch}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
@@ -272,24 +284,24 @@
<scope>test</scope>
</dependency>
<!--
<dependency>
<groupId>org.apache.openwebbeans.test</groupId>
<artifactId>cditest-owb</artifactId>
<version>1.2.8</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jcdi_1.0_spec</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-atinject_1.0_spec</artifactId>
</exclusion>
</exclusions>
</dependency>
-->
<!--
<dependency>
<groupId>org.apache.openwebbeans.test</groupId>
<artifactId>cditest-owb</artifactId>
<version>1.2.8</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jcdi_1.0_spec</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-atinject_1.0_spec</artifactId>
</exclusion>
</exclusions>
</dependency>
-->
<dependency>
<groupId>org.skyscreamer</groupId>
@@ -467,7 +479,9 @@
</module>
</checkstyleRules>
<includes>**/*</includes>
<excludes>.git/**/*,target/**/*,**/target/**/*,.idea/**/*,**/spring.schemas,**/*.svg,mvnw,mvnw.cmd,**/*.policy</excludes>
<excludes>
.git/**/*,target/**/*,**/target/**/*,.idea/**/*,**/spring.schemas,**/*.svg,mvnw,mvnw.cmd,**/*.policy
</excludes>
<sourceDirectories>./</sourceDirectories>
</configuration>
</plugin>
@@ -190,6 +190,29 @@ ClientConfiguration clientConfiguration = ClientConfiguration.builder()
IMPORTANT: Adding a Header supplier as shown in above example allows to inject headers that may change over the time, like authentication JWT tokens. If this is used in the reactive setup, the supplier function *must not* block!
=== Elasticsearch 7 compatibility headers
When using Spring Data Elasticsearch 4 - which uses the Elasticsearch 7 client libraries - and accessing an Elasticsearch cluster that is running on version 8, it is necessary to set the compatibility headers
https://www.elastic.co/guide/en/elasticsearch/reference/8.0/rest-api-compatibility.html[see Elasticserach documentation].
This should be done using a header supplier like shown above:
====
[source,java]
----
ClientConfigurationBuilder configurationBuilder = new ClientConfigurationBuilder();
configurationBuilder //
// ...
.withHeaders(() -> {
HttpHeaders defaultCompatibilityHeaders = new HttpHeaders();
defaultCompatibilityHeaders.add("Accept",
"application/vnd.elasticsearch+json;compatible-with=7");
defaultCompatibilityHeaders.add("Content-Type",
"application/vnd.elasticsearch+json;compatible-with=7");
return defaultCompatibilityHeaders;
});
----
====
[[elasticsearch.clients.logging]]
== Client Logging
@@ -44,7 +44,7 @@ public @interface Document {
* Name of the Elasticsearch index.
* <ul>
* <li>Lowercase only</li>
* <li><Cannot include \, /, *, ?, ", <, >, |, ` ` (space character), ,, #/li>
* <li>Cannot include \, /, *, ?, ", &gt;, &lt;, |, ` ` (space character), ,, #</li>
* <li>Cannot start with -, _, +</li>
* <li>Cannot be . or ..</li>
* <li>Cannot be longer than 255 bytes (note it is bytes, so multi-byte characters will count towards the 255 limit
@@ -17,10 +17,20 @@ package org.springframework.data.elasticsearch.annotations;
/**
* values for the {@link DynamicMapping annotation}
*
*
* @author Peter-Josef Meisch
* @since 4.0
*/
public enum DynamicMappingValue {
True, False, Strict
True("true"), False("false"), Strict("strict");
private final String mappedName;
DynamicMappingValue(String mappedName) {
this.mappedName = mappedName;
}
public String getMappedName() {
return mappedName;
}
}
@@ -26,40 +26,51 @@ package org.springframework.data.elasticsearch.annotations;
* @author Morgan Lutz
*/
public enum FieldType {
Auto, //
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, //
Auto("auto"), //
Text("text"), //
Keyword("keyword"), //
Long("long"), //
Integer("integer"), //
Short("short"), //
Byte("byte"), //
Double("double"), //
Float("float"), //
Half_Float("half_float"), //
Scaled_Float("scaled_float"), //
Date("date"), //
Date_Nanos("date_nanos"), //
Boolean("boolean"), //
Binary("binary"), //
Integer_Range("integer_range"), //
Float_Range("float_range"), //
Long_Range("long_range"), //
Double_Range("double_range"), //
Date_Range("date_range"), //
Ip_Range("ip_range"), //
Object("object"), //
Nested("nested"), //
Ip("ip"), //
TokenCount("token_count"), //
Percolator("percolator"), //
Flattened("flattened"), //
Search_As_You_Type("search_as_you_type"), //
/** @since 4.1 */
Rank_Feature, //
Rank_Feature("rank_feature"), //
/** @since 4.1 */
Rank_Features, //
Rank_Features("rank_features"), //
/** since 4.2 */
Wildcard, //
Wildcard("wildcard"), //
/** @since 4.2 */
Dense_Vector //
Dense_Vector("dense_vector") //
;
private final String mappedName;
FieldType(String mappedName) {
this.mappedName = mappedName;
}
public String getMappedName() {
return mappedName;
}
}
@@ -54,6 +54,7 @@ import org.springframework.util.Assert;
* @author Huw Ayling-Miller
* @author Henrique Amaral
* @author Peter-Josef Meisch
* @author Nic Hines
* @since 3.2
*/
public final class RestClients {
@@ -104,15 +105,14 @@ public final class RestClients {
Duration connectTimeout = clientConfiguration.getConnectTimeout();
if (!connectTimeout.isNegative()) {
requestConfigBuilder.setConnectTimeout(Math.toIntExact(connectTimeout.toMillis()));
requestConfigBuilder.setConnectionRequestTimeout(Math.toIntExact(connectTimeout.toMillis()));
}
Duration timeout = clientConfiguration.getSocketTimeout();
Duration socketTimeout = clientConfiguration.getSocketTimeout();
if (!timeout.isNegative()) {
requestConfigBuilder.setSocketTimeout(Math.toIntExact(timeout.toMillis()));
if (!socketTimeout.isNegative()) {
requestConfigBuilder.setSocketTimeout(Math.toIntExact(socketTimeout.toMillis()));
requestConfigBuilder.setConnectionRequestTimeout(Math.toIntExact(socketTimeout.toMillis()));
}
clientBuilder.setDefaultRequestConfig(requestConfigBuilder.build());
@@ -1452,7 +1452,8 @@ public class RequestConverters {
// encode each part (e.g. index, type and id) separately before merging them into the path
// we prepend "/" to the path part to make this path absolute, otherwise there can be issues with
// paths that start with `-` or contain `:`
URI uri = new URI(null, null, null, -1, '/' + pathPart, null, null);
// the authority must be an empty string and not null, else paths that being with slashes could have them
URI uri = new URI((String) null, "", "/" + pathPart, (String) null, (String) null);
// manually encode any slash that each part may contain
return uri.getRawPath().substring(1).replaceAll("/", "%2F");
} catch (URISyntaxException e) {
@@ -29,7 +29,7 @@ import org.springframework.data.mapping.context.PersistentEntities;
* @author Peter-Josef Meisch
* @since 4.1
*/
class PersistentEntitiesFactoryBean implements FactoryBean<PersistentEntities> {
public class PersistentEntitiesFactoryBean implements FactoryBean<PersistentEntities> {
private final MappingElasticsearchConverter converter;
@@ -79,6 +79,8 @@ import org.springframework.util.Assert;
* @author Peter-Josef Meisch
* @author Roman Puchkovskiy
* @author Subhobrata Dey
* @author Steven Pearce
* @author Anton Naydenov
*/
public abstract class AbstractElasticsearchTemplate implements ElasticsearchOperations, ApplicationContextAware {
@@ -116,6 +118,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
}
copy.setRoutingResolver(routingResolver);
copy.setRefreshPolicy(refreshPolicy);
return copy;
}
@@ -124,7 +124,6 @@ public interface ReactiveSearchOperations {
/**
* Search the index for entities matching the given {@link Query query}.
*
* @param <T>
* @param query must not be {@literal null}.
* @param entityType must not be {@literal null}.
* @param <T>
@@ -138,7 +137,6 @@ public interface ReactiveSearchOperations {
/**
* Search the index for entities matching the given {@link Query query}.
*
* @param <T>
* @param query must not be {@literal null}.
* @param entityType must not be {@literal null}.
* @param resultType the projection result type.
@@ -151,7 +149,6 @@ public interface ReactiveSearchOperations {
/**
* Search the index for entities matching the given {@link Query query}.
*
* @param <T>
* @param query must not be {@literal null}.
* @param entityType must not be {@literal null}.
* @param index the target index, must not be {@literal null}
@@ -166,7 +163,6 @@ public interface ReactiveSearchOperations {
/**
* Search the index for entities matching the given {@link Query query}.
*
* @param <T>
* @param query must not be {@literal null}.
* @param entityType must not be {@literal null}.
* @param resultType the projection result type.
@@ -760,15 +760,17 @@ class RequestFactory {
String indexName = index.getIndexName();
IndexRequest indexRequest;
if (query.getObject() != null) {
String id = StringUtils.isEmpty(query.getId()) ? getPersistentEntityId(query.getObject()) : query.getId();
Object queryObject = query.getObject();
if (queryObject != null) {
String id = StringUtils.isEmpty(query.getId()) ? getPersistentEntityId(queryObject) : query.getId();
// If we have a query id and a document id, do not ask ES to generate one.
if (id != null) {
indexRequest = new IndexRequest(indexName).id(id);
} else {
indexRequest = new IndexRequest(indexName);
}
indexRequest.source(elasticsearchConverter.mapObject(query.getObject()).toJson(), Requests.INDEX_CONTENT_TYPE);
indexRequest.source(elasticsearchConverter.mapObject(queryObject).toJson(), Requests.INDEX_CONTENT_TYPE);
} else if (query.getSource() != null) {
indexRequest = new IndexRequest(indexName).id(query.getId()).source(query.getSource(),
Requests.INDEX_CONTENT_TYPE);
@@ -779,7 +781,8 @@ class RequestFactory {
if (query.getVersion() != null) {
indexRequest.version(query.getVersion());
VersionType versionType = retrieveVersionTypeFromPersistentEntity(query.getObject().getClass());
VersionType versionType = retrieveVersionTypeFromPersistentEntity(
queryObject != null ? queryObject.getClass() : null);
indexRequest.versionType(versionType);
}
@@ -814,15 +817,16 @@ class RequestFactory {
IndexRequestBuilder indexRequestBuilder;
if (query.getObject() != null) {
String id = StringUtils.isEmpty(query.getId()) ? getPersistentEntityId(query.getObject()) : query.getId();
Object queryObject = query.getObject();
if (queryObject != null) {
String id = StringUtils.isEmpty(query.getId()) ? getPersistentEntityId(queryObject) : query.getId();
// If we have a query id and a document id, do not ask ES to generate one.
if (id != null) {
indexRequestBuilder = client.prepareIndex(indexName, type, id);
} else {
indexRequestBuilder = client.prepareIndex(indexName, type);
}
indexRequestBuilder.setSource(elasticsearchConverter.mapObject(query.getObject()).toJson(),
indexRequestBuilder.setSource(elasticsearchConverter.mapObject(queryObject).toJson(),
Requests.INDEX_CONTENT_TYPE);
} else if (query.getSource() != null) {
indexRequestBuilder = client.prepareIndex(indexName, type, query.getId()).setSource(query.getSource(),
@@ -834,7 +838,8 @@ class RequestFactory {
if (query.getVersion() != null) {
indexRequestBuilder.setVersion(query.getVersion());
VersionType versionType = retrieveVersionTypeFromPersistentEntity(query.getObject().getClass());
VersionType versionType = retrieveVersionTypeFromPersistentEntity(
queryObject != null ? queryObject.getClass() : null);
indexRequestBuilder.setVersionType(versionType);
}
@@ -1061,6 +1066,10 @@ class RequestFactory {
query.getRescorerQueries().forEach(rescorer -> sourceBuilder.addRescorer(getQueryRescorerBuilder(rescorer)));
if (query.getScrollTime() != null) {
request.scroll(TimeValue.timeValueMillis(query.getScrollTime().toMillis()));
}
request.source(sourceBuilder);
return request;
}
@@ -1149,6 +1158,10 @@ class RequestFactory {
query.getRescorerQueries().forEach(rescorer -> searchRequestBuilder.addRescorer(getQueryRescorerBuilder(rescorer)));
if (query.getScrollTime() != null) {
searchRequestBuilder.setScroll(TimeValue.timeValueMillis(query.getScrollTime().toMillis()));
}
return searchRequestBuilder;
}
@@ -1695,12 +1708,13 @@ class RequestFactory {
return null;
}
private VersionType retrieveVersionTypeFromPersistentEntity(Class<?> clazz) {
private VersionType retrieveVersionTypeFromPersistentEntity(@Nullable Class<?> clazz) {
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext = elasticsearchConverter
.getMappingContext();
ElasticsearchPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(clazz);
ElasticsearchPersistentEntity<?> persistentEntity = clazz != null ? mappingContext.getPersistentEntity(clazz)
: null;
VersionType versionType = null;
@@ -23,8 +23,7 @@ import java.util.Map;
import java.util.stream.Collectors;
import org.elasticsearch.search.aggregations.Aggregations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.document.NestedMetaData;
@@ -44,12 +43,11 @@ import org.springframework.util.Assert;
* @author Mark Paluch
* @author Roman Puchkovskiy
* @author Matt Gilene
* @author Sascha Woo
* @since 4.0
*/
class SearchHitMapping<T> {
private static final Logger LOGGER = LoggerFactory.getLogger(SearchHitMapping.class);
private final Class<T> type;
private final ElasticsearchConverter converter;
private final MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext;
@@ -173,7 +171,7 @@ class SearchHitMapping<T> {
*/
private SearchHits<?> mapInnerDocuments(SearchHits<SearchDocument> searchHits, Class<T> type) {
if (searchHits.getTotalHits() == 0) {
if (searchHits.isEmpty()) {
return searchHits;
}
@@ -217,7 +215,7 @@ class SearchHitMapping<T> {
searchHits.getAggregations());
}
} catch (Exception e) {
LOGGER.warn("Could not map inner_hits", e);
throw new UncategorizedElasticsearchException("Unable to convert inner hits.", e);
}
return searchHits;
@@ -20,7 +20,7 @@ import org.springframework.data.elasticsearch.core.convert.GeoConverters;
import org.springframework.data.elasticsearch.core.document.Document;
/**
* Interface definition for structures defined in <a href="https://geojson.org/>GeoJSON</a> format. copied from Spring
* Interface definition for structures defined in <a href="https://geojson.org/">GeoJSON</a> format. copied from Spring
* Data Mongodb
*
* @author Christoph Strobl
@@ -156,10 +156,9 @@ public class MappingBuilder {
boolean writeNestedProperties = !isRootObject && (isAnyPropertyAnnotatedWithField(entity) || nestedOrObjectField);
if (writeNestedProperties) {
String type = nestedOrObjectField ? fieldType.toString().toLowerCase()
: FieldType.Object.toString().toLowerCase();
builder.startObject(nestedObjectFieldName).field(FIELD_PARAM_TYPE, type);
String type = nestedOrObjectField ? fieldType.getMappedName() : FieldType.Object.getMappedName();
builder.startObject(nestedObjectFieldName).field(FIELD_PARAM_TYPE, type);
if (nestedOrObjectField && FieldType.Nested == fieldType && parentFieldAnnotation != null
&& parentFieldAnnotation.includeInParent()) {
builder.field("include_in_parent", true);
@@ -364,7 +363,7 @@ public class MappingBuilder {
}
builder.startObject(property.getFieldName()) //
.field(FIELD_PARAM_TYPE, field.type().name().toLowerCase()) //
.field(FIELD_PARAM_TYPE, field.type().getMappedName()) //
.field(MAPPING_ENABLED, false) //
.endObject(); //
} catch (Exception e) {
@@ -392,7 +391,7 @@ public class MappingBuilder {
builder.startObject(property.getFieldName());
if (nestedOrObjectField && dynamicMapping != null) {
builder.field(TYPE_DYNAMIC, dynamicMapping.value().name().toLowerCase());
builder.field(TYPE_DYNAMIC, dynamicMapping.value().getMappedName());
}
addFieldMappingParameters(builder, annotation, nestedOrObjectField);
@@ -441,7 +440,7 @@ public class MappingBuilder {
builder.startObject(property.getFieldName());
if (nestedOrObjectField && dynamicMapping != null) {
builder.field(TYPE_DYNAMIC, dynamicMapping.value().name().toLowerCase());
builder.field(TYPE_DYNAMIC, dynamicMapping.value().getMappedName());
}
addFieldMappingParameters(builder, annotation.mainField(), nestedOrObjectField);
@@ -71,7 +71,7 @@ public final class MappingParameters {
static final String FIELD_PARAM_NULL_VALUE = "null_value";
static final String FIELD_PARAM_POSITION_INCREMENT_GAP = "position_increment_gap";
static final String FIELD_PARAM_POSITIVE_SCORE_IMPACT = "positive_score_impact";
static final String FIELD_PARAM_DIMS = "dims";
static final String FIELD_PARAM_DIMS = "dims";
static final String FIELD_PARAM_SCALING_FACTOR = "scaling_factor";
static final String FIELD_PARAM_SEARCH_ANALYZER = "search_analyzer";
static final String FIELD_PARAM_STORE = "store";
@@ -101,7 +101,7 @@ public final class MappingParameters {
private final NullValueType nullValueType;
private final Integer positionIncrementGap;
private final boolean positiveScoreImpact;
private final Integer dims;
private final Integer dims;
private final String searchAnalyzer;
private final double scalingFactor;
private final Similarity similarity;
@@ -163,7 +163,8 @@ public final class MappingParameters {
positiveScoreImpact = field.positiveScoreImpact();
dims = field.dims();
if (type == FieldType.Dense_Vector) {
Assert.isTrue(dims >= 1 && dims <= 2048, "Invalid required parameter! Dense_Vector value \"dims\" must be between 1 and 2048.");
Assert.isTrue(dims >= 1 && dims <= 2048,
"Invalid required parameter! Dense_Vector value \"dims\" must be between 1 and 2048.");
}
Assert.isTrue(field.enabled() || type == FieldType.Object, "enabled false is only allowed for field type object");
enabled = field.enabled();
@@ -205,7 +206,8 @@ public final class MappingParameters {
positiveScoreImpact = field.positiveScoreImpact();
dims = field.dims();
if (type == FieldType.Dense_Vector) {
Assert.isTrue(dims >= 1 && dims <= 2048, "Invalid required parameter! Dense_Vector value \"dims\" must be between 1 and 2048.");
Assert.isTrue(dims >= 1 && dims <= 2048,
"Invalid required parameter! Dense_Vector value \"dims\" must be between 1 and 2048.");
}
enabled = true;
eagerGlobalOrdinals = field.eagerGlobalOrdinals();
@@ -229,7 +231,7 @@ public final class MappingParameters {
}
if (type != FieldType.Auto) {
builder.field(FIELD_PARAM_TYPE, type.name().toLowerCase());
builder.field(FIELD_PARAM_TYPE, type.getMappedName());
if (type == FieldType.Date) {
List<String> formats = new ArrayList<>();
@@ -15,10 +15,14 @@
*/
package org.springframework.data.elasticsearch.core.join;
import java.util.Objects;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.lang.Nullable;
/**
* @author Subhobrata Dey
* @author Sascha Woo
* @since 4.1
*/
public class JoinField<ID> {
@@ -35,6 +39,7 @@ public class JoinField<ID> {
this(name, null);
}
@PersistenceConstructor
public JoinField(String name, @Nullable ID parent) {
this.name = name;
this.parent = parent;
@@ -52,4 +57,21 @@ public class JoinField<ID> {
public String getName() {
return name;
}
@Override
public int hashCode() {
return Objects.hash(name, parent);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof JoinField)) {
return false;
}
JoinField other = (JoinField) obj;
return Objects.equals(name, other.name) && Objects.equals(parent, other.parent);
}
}
@@ -30,7 +30,7 @@ import org.springframework.lang.Nullable;
* @author Mohsin Husen
* @author Peter-Josef Meisch
* @author Farid Faoudi
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update.html>docs</a>
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update.html">docs</a>
*/
public class UpdateQuery {
@@ -17,6 +17,7 @@ package org.springframework.data.elasticsearch.repository.query;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHitSupport;
import org.springframework.data.elasticsearch.core.SearchHits;
@@ -84,16 +85,11 @@ public class ElasticsearchStringQuery extends AbstractElasticsearchRepositoryQue
.unwrapSearchHits(SearchHitSupport.searchPageFor(searchHits, stringQuery.getPageable()));
}
} else if (queryMethod.isStreamQuery()) {
if (accessor.getPageable().isUnpaged()) {
stringQuery.setPageable(PageRequest.of(0, DEFAULT_STREAM_BATCH_SIZE));
} else {
stringQuery.setPageable(accessor.getPageable());
}
stringQuery.setPageable(
accessor.getPageable().isPaged() ? accessor.getPageable() : PageRequest.of(0, DEFAULT_STREAM_BATCH_SIZE));
result = StreamUtils.createStreamFromIterator(elasticsearchOperations.searchForStream(stringQuery, clazz, index));
} else if (queryMethod.isCollectionQuery()) {
if (accessor.getPageable().isPaged()) {
stringQuery.setPageable(accessor.getPageable());
}
stringQuery.setPageable(accessor.getPageable().isPaged() ? accessor.getPageable() : Pageable.unpaged());
result = elasticsearchOperations.search(stringQuery, clazz, index);
} else {
result = elasticsearchOperations.searchOne(stringQuery, clazz, index);
@@ -105,7 +101,8 @@ public class ElasticsearchStringQuery extends AbstractElasticsearchRepositoryQue
}
protected StringQuery createQuery(ParametersParameterAccessor parameterAccessor) {
String queryString = StringQueryUtil.replacePlaceholders(this.query, parameterAccessor);
String queryString = new StringQueryUtil(elasticsearchOperations.getElasticsearchConverter().getConversionService())
.replacePlaceholders(this.query, parameterAccessor);
return new StringQuery(queryString);
}
@@ -47,7 +47,9 @@ public class ReactiveElasticsearchStringQuery extends AbstractReactiveElasticsea
@Override
protected StringQuery createQuery(ElasticsearchParameterAccessor parameterAccessor) {
String queryString = StringQueryUtil.replacePlaceholders(this.query, parameterAccessor);
String queryString = new StringQueryUtil(
getElasticsearchOperations().getElasticsearchConverter().getConversionService()).replacePlaceholders(this.query,
parameterAccessor);
return new StringQuery(queryString);
}
@@ -15,41 +15,59 @@
*/
package org.springframework.data.elasticsearch.repository.support;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.elasticsearch.core.convert.DateTimeConverters;
import org.springframework.data.elasticsearch.repository.query.ElasticsearchStringQuery;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.NumberUtils;
/**
* @author Peter-Josef Meisch
* @author Niklas Herder
*/
final public class StringQueryUtil {
private static final Pattern PARAMETER_PLACEHOLDER = Pattern.compile("\\?(\\d+)");
private static final GenericConversionService conversionService = new GenericConversionService();
{
if (!conversionService.canConvert(java.util.Date.class, String.class)) {
conversionService.addConverter(DateTimeConverters.JavaDateConverter.INSTANCE);
}
if (ClassUtils.isPresent("org.joda.time.DateTimeZone", ElasticsearchStringQuery.class.getClassLoader())) {
if (!conversionService.canConvert(org.joda.time.ReadableInstant.class, String.class)) {
conversionService.addConverter(DateTimeConverters.JodaDateTimeConverter.INSTANCE);
}
if (!conversionService.canConvert(org.joda.time.LocalDateTime.class, String.class)) {
conversionService.addConverter(DateTimeConverters.JodaLocalDateTimeConverter.INSTANCE);
}
}
}
private final ConversionService conversionService;
private final GenericConversionService genericConversionService;
private StringQueryUtil() {}
public StringQueryUtil(ConversionService conversionService) {
public static String replacePlaceholders(String input, ParameterAccessor accessor) {
Assert.notNull(conversionService, "conversionService must not be null");
this.conversionService = conversionService;
genericConversionService = setupGenericConversionService();
}
private GenericConversionService setupGenericConversionService() {
GenericConversionService genericConversionService = new GenericConversionService();
if (!genericConversionService.canConvert(java.util.Date.class, String.class)) {
genericConversionService.addConverter(DateTimeConverters.JavaDateConverter.INSTANCE);
}
if (ClassUtils.isPresent("org.joda.time.DateTimeZone", ElasticsearchStringQuery.class.getClassLoader())) {
if (!genericConversionService.canConvert(org.joda.time.ReadableInstant.class, String.class)) {
genericConversionService.addConverter(DateTimeConverters.JodaDateTimeConverter.INSTANCE);
}
if (!genericConversionService.canConvert(org.joda.time.LocalDateTime.class, String.class)) {
genericConversionService.addConverter(DateTimeConverters.JodaLocalDateTimeConverter.INSTANCE);
}
}
return genericConversionService;
}
public String replacePlaceholders(String input, ParameterAccessor accessor) {
Matcher matcher = PARAMETER_PLACEHOLDER.matcher(input);
String result = input;
@@ -62,7 +80,7 @@ final public class StringQueryUtil {
return result;
}
private static String getParameterWithIndex(ParameterAccessor accessor, int index) {
private String getParameterWithIndex(ParameterAccessor accessor, int index) {
Object parameter = accessor.getBindableValue(index);
String parameterValue = "null";
@@ -70,20 +88,48 @@ final public class StringQueryUtil {
// noinspection ConstantConditions
if (parameter != null) {
parameterValue = convert(parameter);
}
return parameterValue;
}
private String convert(Object parameter) {
if (Collection.class.isAssignableFrom(parameter.getClass())) {
Collection<?> collectionParam = (Collection<?>) parameter;
StringBuilder sb = new StringBuilder("[");
sb.append(collectionParam.stream().map(o -> {
if (o instanceof String) {
return "\"" + convert(o) + "\"";
} else {
return convert(o);
}
}).collect(Collectors.joining(",")));
sb.append("]");
return sb.toString();
} else {
String parameterValue = "null";
if (conversionService.canConvert(parameter.getClass(), String.class)) {
String converted = conversionService.convert(parameter, String.class);
if (converted != null) {
parameterValue = converted;
}
} else if (genericConversionService.canConvert(parameter.getClass(), String.class)) {
String converted = genericConversionService.convert(parameter, String.class);
if (converted != null) {
parameterValue = converted;
}
} else {
parameterValue = parameter.toString();
}
parameterValue = parameterValue.replaceAll("\"", Matcher.quoteReplacement("\\\""));
return parameterValue;
}
parameterValue = parameterValue.replaceAll("\"", Matcher.quoteReplacement("\\\""));
return parameterValue;
}
}
+8
View File
@@ -1,6 +1,13 @@
Spring Data Elasticsearch Changelog
===================================
Changes in version 4.2.3 (2021-07-16)
-------------------------------------
* #1866 - Queries defined with `@Query` are not using registered converters for parameter conversion.
* #1858 - Collection parameters for @Query-annotated methods get escaped wrongly.
* #1846 - Missing hashCode and equals methods in JoinField.
Changes in version 4.2.2 (2021-06-22)
-------------------------------------
* #1834 - TopMetricsAggregation NamedObjectNotFoundException: unknown field [top_metrics].
@@ -1637,5 +1644,6 @@ Release Notes - Spring Data Elasticsearch - Version 1.0 M1 (2014-02-07)
+9 -1
View File
@@ -1,4 +1,4 @@
Spring Data Elasticsearch 4.2.2 (2021.0.2)
Spring Data Elasticsearch 4.2.10 (2021.0.10)
Copyright (c) [2013-2021] Pivotal Software, Inc.
This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -20,6 +20,14 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
@@ -50,10 +50,13 @@ import org.elasticsearch.cluster.metadata.AliasMetadata;
import org.elasticsearch.common.lucene.search.function.CombineFunction;
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
import org.elasticsearch.index.VersionType;
import org.elasticsearch.index.query.InnerHitBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder.FilterFunctionBuilder;
import org.elasticsearch.index.query.functionscore.GaussDecayFunctionBuilder;
import org.elasticsearch.join.query.HasChildQueryBuilder;
import org.elasticsearch.join.query.JoinQueryBuilders;
import org.elasticsearch.join.query.ParentIdQueryBuilder;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
@@ -1129,7 +1132,8 @@ public abstract class ElasticsearchTemplateTests {
Collection<String> ids = IntStream.rangeClosed(1, 10).mapToObj(i -> nextIdAsString()).collect(Collectors.toList());
ids.add(referenceId);
ids.stream()
.map(id -> getIndexQuery(SampleEntity.builder().id(id).message(sampleMessage).version(System.currentTimeMillis()).build()))
.map(id -> getIndexQuery(
SampleEntity.builder().id(id).message(sampleMessage).version(System.currentTimeMillis()).build()))
.forEach(indexQuery -> operations.index(indexQuery, index));
indexOperations.refresh();
@@ -1144,7 +1148,8 @@ public abstract class ElasticsearchTemplateTests {
assertThat(searchHits.getTotalHits()).isEqualTo(10);
assertThat(searchHits.getSearchHits()).hasSize(5);
Collection<String> returnedIds = searchHits.getSearchHits().stream().map(SearchHit::getId).collect(Collectors.toList());
Collection<String> returnedIds = searchHits.getSearchHits().stream().map(SearchHit::getId)
.collect(Collectors.toList());
moreLikeThisQuery.setPageable(PageRequest.of(1, 5));
@@ -3027,6 +3032,46 @@ public abstract class ElasticsearchTemplateTests {
indexOperations.removeAlias(aliasQuery);
}
@Test // #1997
@DisplayName("should return document with inner hits size zero")
void shouldReturnDocumentWithInnerHitsSizeZero() {
// given
SampleJoinEntity sampleQuestionEntity1 = new SampleJoinEntity();
sampleQuestionEntity1.setUuid("q1");
sampleQuestionEntity1.setText("This is a question");
sampleQuestionEntity1.setMyJoinField(new JoinField<>("question"));
SampleJoinEntity sampleAnswerEntity1 = new SampleJoinEntity();
sampleAnswerEntity1.setUuid("a1");
sampleAnswerEntity1.setText("This is an answer");
sampleAnswerEntity1.setMyJoinField(new JoinField<>("answer", sampleQuestionEntity1.getUuid()));
SampleJoinEntity sampleAnswerEntity2 = new SampleJoinEntity();
sampleAnswerEntity1.setUuid("a2");
sampleAnswerEntity1.setText("This is an answer");
sampleAnswerEntity1.setMyJoinField(new JoinField<>("answer", sampleQuestionEntity1.getUuid()));
IndexOperations indexOps = operations.indexOps(SampleJoinEntity.class);
operations.save(Arrays.asList(sampleQuestionEntity1, sampleAnswerEntity1, sampleAnswerEntity2));
indexOps.refresh();
// when
Query query = new NativeSearchQueryBuilder().withQuery(
JoinQueryBuilders.hasChildQuery("answer", matchAllQuery(), org.apache.lucene.search.join.ScoreMode.Avg)
.innerHit(new InnerHitBuilder("innerHits").setSize(0)))
.build();
SearchHits<SampleJoinEntity> searchHits = operations.search(query, SampleJoinEntity.class);
// then
assertThat(searchHits).isNotNull();
assertThat(searchHits.getTotalHits()).isEqualTo(1);
assertThat(searchHits.getSearchHits()).hasSize(1);
assertThat(searchHits.getSearchHit(0).getInnerHits().size()).isEqualTo(1);
assertThat(searchHits.getSearchHit(0).getInnerHits("innerHits").getTotalHits()).isEqualTo(1);
}
@Test // DATAES-541
public void shouldRemoveAlias() {
@@ -3794,6 +3839,22 @@ public abstract class ElasticsearchTemplateTests {
assertThat(explanation).isNotNull();
}
@Test // #1893
@DisplayName("should index document from source with version")
void shouldIndexDocumentFromSourceWithVersion() {
String source = "{\n" + //
" \"answer\": 42\n" + //
"}";
IndexQuery query = new IndexQueryBuilder() //
.withId("42") //
.withSource(source) //
.withVersion(42L) //
.build();
operations.index(query, IndexCoordinates.of(INDEX_NAME_SAMPLE_ENTITY));
}
// region entities
@Document(indexName = INDEX_NAME_SAMPLE_ENTITY)
@Setting(shards = 1, replicas = 0, refreshInterval = "-1")
@@ -4572,5 +4633,5 @@ public abstract class ElasticsearchTemplateTests {
this.text = text;
}
}
//endregion
// endregion
}
@@ -308,8 +308,10 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "ignore-above-index")
static class IgnoreAboveEntity {
@Nullable @Id private String id;
@Nullable @Field(type = FieldType.Keyword, ignoreAbove = 10) private String message;
@Nullable
@Id private String id;
@Nullable
@Field(type = FieldType.Keyword, ignoreAbove = 10) private String message;
@Nullable
public String getId() {
@@ -334,13 +336,17 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "fieldname-index")
static class IdEntity {
@Nullable @Id @Field("id-property") private String id;
@Nullable
@Id
@Field("id-property") private String id;
}
@Document(indexName = "fieldname-index")
static class TextEntity {
@Nullable @Id @Field("id-property") private String id;
@Nullable
@Id
@Field("id-property") private String id;
@Field(name = "text-property", type = FieldType.Text) //
@Nullable private String textProperty;
@@ -349,42 +355,57 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "fieldname-index")
static class MappingEntity {
@Nullable @Id @Field("id-property") private String id;
@Nullable
@Id
@Field("id-property") private String id;
@Field("mapping-property") @Mapping(mappingPath = "/mappings/test-field-analyzed-mappings.json") //
@Field("mapping-property")
@Mapping(mappingPath = "/mappings/test-field-analyzed-mappings.json") //
@Nullable private byte[] mappingProperty;
}
@Document(indexName = "fieldname-index")
static class GeoPointEntity {
@Nullable @Id @Field("id-property") private String id;
@Nullable
@Id
@Field("id-property") private String id;
@Nullable @Field("geopoint-property") private GeoPoint geoPoint;
@Nullable
@Field("geopoint-property") private GeoPoint geoPoint;
}
@Document(indexName = "fieldname-index")
static class CircularEntity {
@Nullable @Id @Field("id-property") private String id;
@Nullable
@Id
@Field("id-property") private String id;
@Nullable @Field(name = "circular-property", type = FieldType.Object, ignoreFields = { "circular-property" }) //
@Nullable
@Field(name = "circular-property", type = FieldType.Object, ignoreFields = { "circular-property" }) //
private CircularEntity circularProperty;
}
@Document(indexName = "fieldname-index")
static class CompletionEntity {
@Nullable @Id @Field("id-property") private String id;
@Nullable
@Id
@Field("id-property") private String id;
@Nullable @Field("completion-property") @CompletionField(maxInputLength = 100) //
@Nullable
@Field("completion-property")
@CompletionField(maxInputLength = 100) //
private Completion suggest;
}
@Document(indexName = "fieldname-index")
static class MultiFieldEntity {
@Nullable @Id @Field("id-property") private String id;
@Nullable
@Id
@Field("id-property") private String id;
@Nullable //
@MultiField(mainField = @Field(name = "main-field", type = FieldType.Text, analyzer = "whitespace"),
@@ -396,11 +417,15 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "test-index-book-mapping-builder")
static class Book {
@Nullable @Id private String id;
@Nullable
@Id private String id;
@Nullable private String name;
@Nullable @Field(type = FieldType.Object) private Author author;
@Nullable @Field(type = FieldType.Nested) private Map<Integer, Collection<String>> buckets = new HashMap<>();
@Nullable @MultiField(mainField = @Field(type = FieldType.Text, analyzer = "whitespace"),
@Nullable
@Field(type = FieldType.Object) private Author author;
@Nullable
@Field(type = FieldType.Nested) private Map<Integer, Collection<String>> buckets = new HashMap<>();
@Nullable
@MultiField(mainField = @Field(type = FieldType.Text, analyzer = "whitespace"),
otherFields = { @InnerField(suffix = "prefix", type = FieldType.Text, analyzer = "stop",
searchAnalyzer = "standard") }) private String description;
@@ -452,9 +477,10 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "test-index-simple-recursive-mapping-builder")
static class SimpleRecursiveEntity {
@Nullable @Id private String id;
@Nullable @Field(type = FieldType.Object,
ignoreFields = { "circularObject" }) private SimpleRecursiveEntity circularObject;
@Nullable
@Id private String id;
@Nullable
@Field(type = FieldType.Object, ignoreFields = { "circularObject" }) private SimpleRecursiveEntity circularObject;
@Nullable
public String getId() {
@@ -477,10 +503,14 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "test-copy-to-mapping-builder")
static class CopyToEntity {
@Nullable @Id private String id;
@Nullable @Field(type = FieldType.Keyword, copyTo = "name") private String firstName;
@Nullable @Field(type = FieldType.Keyword, copyTo = "name") private String lastName;
@Nullable @Field(type = FieldType.Keyword) private String name;
@Nullable
@Id private String id;
@Nullable
@Field(type = FieldType.Keyword, copyTo = "name") private String firstName;
@Nullable
@Field(type = FieldType.Keyword, copyTo = "name") private String lastName;
@Nullable
@Field(type = FieldType.Keyword) private String name;
@Nullable
public String getId() {
@@ -522,9 +552,12 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "test-index-normalizer-mapping-builder")
@Setting(settingPath = "/settings/test-normalizer.json")
static class NormalizerEntity {
@Nullable @Id private String id;
@Nullable @Field(type = FieldType.Keyword, normalizer = "lower_case_normalizer") private String name;
@Nullable @MultiField(mainField = @Field(type = FieldType.Text), otherFields = { @InnerField(suffix = "lower_case",
@Nullable
@Id private String id;
@Nullable
@Field(type = FieldType.Keyword, normalizer = "lower_case_normalizer") private String name;
@Nullable
@MultiField(mainField = @Field(type = FieldType.Text), otherFields = { @InnerField(suffix = "lower_case",
type = FieldType.Keyword, normalizer = "lower_case_normalizer") }) private String description;
@Nullable
@@ -582,7 +615,8 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "test-index-sample-inherited-mapping-builder")
static class SampleInheritedEntity extends AbstractInheritedEntity {
@Nullable @Field(type = Text, index = false, store = true, analyzer = "standard") private String message;
@Nullable
@Field(type = Text, index = false, store = true, analyzer = "standard") private String message;
@Nullable
public String getMessage() {
@@ -627,9 +661,11 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "test-index-stock-mapping-builder")
static class StockPrice {
@Nullable @Id private String id;
@Nullable
@Id private String id;
@Nullable private String symbol;
@Nullable @Field(type = FieldType.Double) private BigDecimal price;
@Nullable
@Field(type = FieldType.Double) private BigDecimal price;
@Nullable
public String getId() {
@@ -660,8 +696,10 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
}
static class AbstractInheritedEntity {
@Nullable @Id private String id;
@Nullable @Field(type = FieldType.Date, format = DateFormat.date_time, index = false) private Date createdDate;
@Nullable
@Id private String id;
@Nullable
@Field(type = FieldType.Date, format = DateFormat.date_time, index = false) private Date createdDate;
@Nullable
public String getId() {
@@ -684,19 +722,25 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "test-index-geo-mapping-builder")
static class GeoEntity {
@Nullable @Id private String id;
@Nullable
@Id private String id;
// geo shape - Spring Data
@Nullable private Box box;
@Nullable private Circle circle;
@Nullable private Polygon polygon;
// geo point - Custom implementation + Spring Data
@Nullable @GeoPointField private Point pointA;
@Nullable
@GeoPointField private Point pointA;
@Nullable private GeoPoint pointB;
@Nullable @GeoPointField private String pointC;
@Nullable @GeoPointField private double[] pointD;
@Nullable
@GeoPointField private String pointC;
@Nullable
@GeoPointField private double[] pointD;
// geo shape, until e have the classes for this, us a strng
@Nullable @GeoShapeField private String shape1;
@Nullable @GeoShapeField(coerce = true, ignoreMalformed = true, ignoreZValue = false,
@Nullable
@GeoShapeField private String shape1;
@Nullable
@GeoShapeField(coerce = true, ignoreMalformed = true, ignoreZValue = false,
orientation = GeoShapeField.Orientation.clockwise) private String shape2;
@Nullable
@@ -792,7 +836,8 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "test-index-user-mapping-builder")
static class User {
@Nullable @Id private String id;
@Nullable
@Id private String id;
@Field(type = FieldType.Nested, ignoreFields = { "users" }) private Set<Group> groups = new HashSet<>();
}
@@ -800,7 +845,8 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "test-index-group-mapping-builder")
static class Group {
@Nullable @Id String id;
@Nullable
@Id String id;
@Field(type = FieldType.Nested, ignoreFields = { "groups" }) private Set<User> users = new HashSet<>();
}
@@ -819,8 +865,10 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "completion")
static class CompletionDocument {
@Nullable @Id private String id;
@Nullable @CompletionField(contexts = { @CompletionContext(name = "location", type = ContextMapping.Type.GEO,
@Nullable
@Id private String id;
@Nullable
@CompletionField(contexts = { @CompletionContext(name = "location", type = ContextMapping.Type.GEO,
path = "proppath") }) private Completion suggest;
@Nullable
@@ -844,7 +892,8 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "test-index-entity-with-seq-no-primary-term-mapping-builder")
static class EntityWithSeqNoPrimaryTerm {
@Nullable @Field(type = Object) private SeqNoPrimaryTerm seqNoPrimaryTerm;
@Nullable
@Field(type = Object) private SeqNoPrimaryTerm seqNoPrimaryTerm;
@Nullable
public SeqNoPrimaryTerm getSeqNoPrimaryTerm() {
@@ -857,10 +906,14 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
}
static class RankFeatureEntity {
@Nullable @Id private String id;
@Nullable @Field(type = FieldType.Rank_Feature) private Integer pageRank;
@Nullable @Field(type = FieldType.Rank_Feature, positiveScoreImpact = false) private Integer urlLength;
@Nullable @Field(type = FieldType.Rank_Features) private Map<String, Integer> topics;
@Nullable
@Id private String id;
@Nullable
@Field(type = FieldType.Rank_Feature) private Integer pageRank;
@Nullable
@Field(type = FieldType.Rank_Feature, positiveScoreImpact = false) private Integer urlLength;
@Nullable
@Field(type = FieldType.Rank_Features) private Map<String, Integer> topics;
@Nullable
public String getId() {
@@ -901,16 +954,23 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "termvectors-test")
static class TermVectorFieldEntity {
@Nullable @Id private String id;
@Nullable @Field(type = FieldType.Text, termVector = TermVector.no) private String no;
@Nullable @Field(type = FieldType.Text, termVector = TermVector.yes) private String yes;
@Nullable @Field(type = FieldType.Text, termVector = TermVector.with_positions) private String with_positions;
@Nullable @Field(type = FieldType.Text, termVector = TermVector.with_offsets) private String with_offsets;
@Nullable @Field(type = FieldType.Text,
termVector = TermVector.with_positions_offsets) private String with_positions_offsets;
@Nullable @Field(type = FieldType.Text,
@Nullable
@Id private String id;
@Nullable
@Field(type = FieldType.Text, termVector = TermVector.no) private String no;
@Nullable
@Field(type = FieldType.Text, termVector = TermVector.yes) private String yes;
@Nullable
@Field(type = FieldType.Text, termVector = TermVector.with_positions) private String with_positions;
@Nullable
@Field(type = FieldType.Text, termVector = TermVector.with_offsets) private String with_offsets;
@Nullable
@Field(type = FieldType.Text, termVector = TermVector.with_positions_offsets) private String with_positions_offsets;
@Nullable
@Field(type = FieldType.Text,
termVector = TermVector.with_positions_payloads) private String with_positions_payloads;
@Nullable @Field(type = FieldType.Text,
@Nullable
@Field(type = FieldType.Text,
termVector = TermVector.with_positions_offsets_payloads) private String with_positions_offsets_payloads;
@Nullable
@@ -988,8 +1048,10 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "wildcard-test")
static class WildcardEntity {
@Nullable @Field(type = Wildcard) private String wildcardWithoutParams;
@Nullable @Field(type = Wildcard, nullValue = "WILD", ignoreAbove = 42) private String wildcardWithParams;
@Nullable
@Field(type = Wildcard) private String wildcardWithoutParams;
@Nullable
@Field(type = Wildcard, nullValue = "WILD", ignoreAbove = 42) private String wildcardWithParams;
@Nullable
public String getWildcardWithoutParams() {
@@ -1013,8 +1075,10 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "disabled-entity-mapping")
@Mapping(enabled = false)
static class DisabledMappingEntity {
@Nullable @Id private String id;
@Nullable @Field(type = Text) private String text;
@Nullable
@Id private String id;
@Nullable
@Field(type = Text) private String text;
@Nullable
public String getId() {
@@ -1037,9 +1101,13 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "disabled-property-mapping")
static class DisabledMappingProperty {
@Nullable @Id private String id;
@Nullable @Field(type = Text) private String text;
@Nullable @Mapping(enabled = false) @Field(type = Object) private Object object;
@Nullable
@Id private String id;
@Nullable
@Field(type = Text) private String text;
@Nullable
@Mapping(enabled = false)
@Field(type = Object) private Object object;
@Nullable
public String getId() {
@@ -1071,8 +1139,10 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "densevector-test")
static class DenseVectorEntity {
@Nullable @Id private String id;
@Nullable @Field(type = Dense_Vector, dims = 3) private float[] dense_vector;
@Nullable
@Id private String id;
@Nullable
@Field(type = Dense_Vector, dims = 3) private float[] dense_vector;
@Nullable
public String getId() {
@@ -1097,11 +1167,15 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@DynamicMapping(DynamicMappingValue.False)
static class DynamicMappingEntity {
@Nullable @DynamicMapping(DynamicMappingValue.Strict) @Field(type = FieldType.Object) private Author author;
@Nullable @DynamicMapping(DynamicMappingValue.False) @Field(
type = FieldType.Object) private Map<String, Object> objectMap;
@Nullable @DynamicMapping(DynamicMappingValue.False) @Field(
type = FieldType.Nested) private List<Map<String, Object>> nestedObjectMap;
@Nullable
@DynamicMapping(DynamicMappingValue.Strict)
@Field(type = FieldType.Object) private Author author;
@Nullable
@DynamicMapping(DynamicMappingValue.False)
@Field(type = FieldType.Object) private Map<String, Object> objectMap;
@Nullable
@DynamicMapping(DynamicMappingValue.False)
@Field(type = FieldType.Nested) private List<Map<String, Object>> nestedObjectMap;
@Nullable
public Author getAuthor() {
@@ -1113,4 +1187,71 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
}
}
@Document(indexName = "allTypes")
private static class EntityWithAllTypes {
@Nullable
@Field(type = FieldType.Auto) String autoField;
@Nullable
@Field(type = FieldType.Text) String textField;
@Nullable
@Field(type = FieldType.Keyword) String keywordField;
@Nullable
@Field(type = FieldType.Long) String longField;
@Nullable
@Field(type = FieldType.Integer) String integerField;
@Nullable
@Field(type = FieldType.Short) String shortField;
@Nullable
@Field(type = FieldType.Byte) String byteField;
@Nullable
@Field(type = FieldType.Double) String doubleField;
@Nullable
@Field(type = FieldType.Float) String floatField;
@Nullable
@Field(type = FieldType.Half_Float) String halfFloatField;
@Nullable
@Field(type = FieldType.Scaled_Float) String scaledFloatField;
@Nullable
@Field(type = FieldType.Date) String dateField;
@Nullable
@Field(type = FieldType.Date_Nanos) String dateNanosField;
@Nullable
@Field(type = FieldType.Boolean) String booleanField;
@Nullable
@Field(type = FieldType.Binary) String binaryField;
@Nullable
@Field(type = FieldType.Integer_Range) String integerRangeField;
@Nullable
@Field(type = FieldType.Float_Range) String floatRangeField;
@Nullable
@Field(type = FieldType.Long_Range) String longRangeField;
@Nullable
@Field(type = FieldType.Double_Range) String doubleRangeField;
@Nullable
@Field(type = FieldType.Date_Range) String dateRangeField;
@Nullable
@Field(type = FieldType.Ip_Range) String ipRangeField;
@Nullable
@Field(type = FieldType.Object) String objectField;
@Nullable
@Field(type = FieldType.Nested) String nestedField;
@Nullable
@Field(type = FieldType.Ip) String ipField;
@Nullable
@Field(type = FieldType.TokenCount, analyzer = "standard") String tokenCountField;
@Nullable
@Field(type = FieldType.Percolator) String percolatorField;
@Nullable
@Field(type = FieldType.Flattened) String flattenedField;
@Nullable
@Field(type = FieldType.Search_As_You_Type) String searchAsYouTypeField;
@Nullable
@Field(type = FieldType.Rank_Feature) String rankFeatureField;
@Nullable
@Field(type = FieldType.Rank_Features) String rankFeaturesField;
@Nullable
@Field(type = FieldType.Wildcard) String wildcardField;
@Nullable
@Field(type = FieldType.Dense_Vector, dims = 1) String denseVectorField;
}
}
@@ -29,10 +29,12 @@ import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Routing;
import org.springframework.data.elasticsearch.annotations.Setting;
import org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate;
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.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
@@ -41,6 +43,7 @@ import org.springframework.test.context.ContextConfiguration;
/**
* @author Peter-Josef Meisch
* @author Anton Naydenov
*/
@SuppressWarnings("ConstantConditions")
@SpringIntegrationTest
@@ -118,6 +121,21 @@ public class ElasticsearchOperationsRoutingTests {
assertThat(searchHits.getSearchHit(0).getRouting()).isEqualTo(ID_2);
}
@Test
void shouldCreateACopyOfTheClientWithRefreshPolicy() {
// given
AbstractElasticsearchTemplate sourceTemplate = (AbstractElasticsearchTemplate) operations;
SimpleElasticsearchMappingContext mappingContext = new SimpleElasticsearchMappingContext();
DefaultRoutingResolver defaultRoutingResolver = new DefaultRoutingResolver(mappingContext);
// when
ElasticsearchOperations operationsCopy = this.operations.withRouting(defaultRoutingResolver);
AbstractElasticsearchTemplate copyTemplate = (AbstractElasticsearchTemplate) operationsCopy;
// then
assertThat(sourceTemplate.getRefreshPolicy()).isEqualTo(copyTemplate.getRefreshPolicy());
}
@Document(indexName = INDEX)
@Setting(shards = 5)
@Routing("routing")
@@ -1610,19 +1610,18 @@ public abstract class CustomMethodRepositoryBaseTests {
assertThat((nextPageable.getPageNumber())).isEqualTo(1);
}
private List<SampleEntity> createSampleEntities(String type, int numberOfEntities) {
@Test // #1917
@DisplayName("shouldReturnAllDocumentsWithUnpagedQuery")
void shouldReturnAllDocumentsWithUnpagedQuery() {
List<SampleEntity> entities = new ArrayList<>();
for (int i = 0; i < numberOfEntities; i++) {
SampleEntity entity = new SampleEntity();
entity.setId(UUID.randomUUID().toString());
entity.setAvailable(true);
entity.setMessage("Message");
entity.setType(type);
entities.add(entity);
}
List<SampleEntity> entities = createSampleEntities("abc", 20);
repository.saveAll(entities);
return entities;
SearchHits<SampleEntity> searchHits = repository.searchWithQueryByMessageUnpaged("Message");
assertThat(searchHits).isNotNull();
assertThat((searchHits.getTotalHits())).isEqualTo(20);
assertThat(searchHits.getSearchHits()).hasSize(20);
}
@Test // DATAES-891
@@ -1647,6 +1646,21 @@ public abstract class CustomMethodRepositoryBaseTests {
assertThat(count).isEqualTo(20);
}
private List<SampleEntity> createSampleEntities(String type, int numberOfEntities) {
List<SampleEntity> entities = new ArrayList<>();
for (int i = 0; i < numberOfEntities; i++) {
SampleEntity entity = new SampleEntity();
entity.setId(UUID.randomUUID().toString());
entity.setAvailable(true);
entity.setMessage("Message");
entity.setType(type);
entities.add(entity);
}
return entities;
}
@Document(indexName = "test-index-sample-repositories-custom-method")
static class SampleEntity {
@Nullable @Id private String id;
@@ -1854,6 +1868,9 @@ public abstract class CustomMethodRepositoryBaseTests {
@Query("{\"match\": {\"message\": \"?0\"}}")
SearchPage<SampleEntity> searchWithQueryByMessage(String message, Pageable pageable);
@Query("{\"match\": {\"message\": \"?0\"}}")
SearchHits<SampleEntity> searchWithQueryByMessageUnpaged(String message);
@CountQuery("{\"bool\" : {\"must\" : {\"term\" : {\"type\" : \"?0\"}}}}")
long countWithQueryByType(String type);
}
@@ -0,0 +1,78 @@
/*
* 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.repository.query;
import java.util.ArrayList;
import java.util.Collection;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.lang.Nullable;
/**
* @author Peter-Josef Meisch
*/
public class ElasticsearchStringQueryUnitTestBase {
protected ElasticsearchConverter setupConverter() {
MappingElasticsearchConverter converter = new MappingElasticsearchConverter(
new SimpleElasticsearchMappingContext());
Collection<Converter<?, ?>> converters = new ArrayList<>();
converters.add(ElasticsearchStringQueryUnitTests.CarConverter.INSTANCE);
CustomConversions customConversions = new ElasticsearchCustomConversions(converters);
converter.setConversions(customConversions);
converter.afterPropertiesSet();
return converter;
}
static class Car {
@Nullable private String name;
@Nullable private String model;
@Nullable
public String getName() {
return name;
}
public void setName(@Nullable String name) {
this.name = name;
}
@Nullable
public String getModel() {
return model;
}
public void setModel(@Nullable String model) {
this.model = model;
}
}
enum CarConverter implements Converter<Car, String> {
INSTANCE;
@Override
public String convert(ElasticsearchStringQueryUnitTests.Car car) {
return (car.getName() != null ? car.getName() : "null") + '-'
+ (car.getModel() != null ? car.getModel() : "null");
}
}
}
@@ -16,8 +16,10 @@
package org.springframework.data.elasticsearch.repository.query;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
@@ -39,9 +41,6 @@ import org.springframework.data.elasticsearch.annotations.MultiField;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.core.query.StringQuery;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.Repository;
@@ -51,16 +50,16 @@ import org.springframework.lang.Nullable;
/**
* @author Christoph Strobl
* @author Peter-Josef Meisch
* @author Niklas Herder
*/
@ExtendWith(MockitoExtension.class)
public class ElasticsearchStringQueryUnitTests {
public class ElasticsearchStringQueryUnitTests extends ElasticsearchStringQueryUnitTestBase {
@Mock ElasticsearchOperations operations;
ElasticsearchConverter converter;
@BeforeEach
public void setUp() {
converter = new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext());
when(operations.getElasticsearchConverter()).thenReturn(setupConverter());
}
@Test // DATAES-552
@@ -95,7 +94,42 @@ public class ElasticsearchStringQueryUnitTests {
.isEqualTo("{\"bool\":{\"must\": [{\"match\": {\"prefix\": {\"name\" : \"hello \\\"Stranger\\\"\"}}]}}");
}
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, String... args)
@Test // #1858
@DisplayName("should only quote String query parameters")
void shouldOnlyEscapeStringQueryParameters() throws Exception {
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByAge", Integer.valueOf(30));
assertThat(query).isInstanceOf(StringQuery.class);
assertThat(((StringQuery) query).getSource()).isEqualTo("{ 'bool' : { 'must' : { 'term' : { 'age' : 30 } } } }");
}
@Test // #1858
@DisplayName("should only quote String collection query parameters")
void shouldOnlyEscapeStringCollectionQueryParameters() throws Exception {
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByAgeIn",
new ArrayList<>(Arrays.asList(30, 35, 40)));
assertThat(query).isInstanceOf(StringQuery.class);
assertThat(((StringQuery) query).getSource())
.isEqualTo("{ 'bool' : { 'must' : { 'term' : { 'age' : [30,35,40] } } } }");
}
@Test // #1858
@DisplayName("should escape Strings in collection query parameters")
void shouldEscapeStringsInCollectionsQueryParameters() throws Exception {
final List<String> another_string = Arrays.asList("hello \"Stranger\"", "Another string");
List<String> params = new ArrayList<>(another_string);
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByNameIn", params);
assertThat(query).isInstanceOf(StringQuery.class);
assertThat(((StringQuery) query).getSource()).isEqualTo(
"{ 'bool' : { 'must' : { 'terms' : { 'name' : [\"hello \\\"Stranger\\\"\",\"Another string\"] } } } }");
}
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, Object... args)
throws NoSuchMethodException {
Class<?>[] argTypes = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);
@@ -103,6 +137,22 @@ public class ElasticsearchStringQueryUnitTests {
ElasticsearchStringQuery elasticsearchStringQuery = queryForMethod(queryMethod);
return elasticsearchStringQuery.createQuery(new ElasticsearchParametersParameterAccessor(queryMethod, args));
}
@Test // #1866
@DisplayName("should use converter on parameters")
void shouldUseConverterOnParameters() throws NoSuchMethodException {
Car car = new Car();
car.setName("Toyota");
car.setModel("Prius");
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByCar", car);
assertThat(query).isInstanceOf(StringQuery.class);
assertThat(((StringQuery) query).getSource())
.isEqualTo("{ 'bool' : { 'must' : { 'term' : { 'car' : 'Toyota-Prius' } } } }");
}
private ElasticsearchStringQuery queryForMethod(ElasticsearchQueryMethod queryMethod) {
return new ElasticsearchStringQuery(queryMethod, operations, queryMethod.getAnnotatedQuery());
}
@@ -111,36 +161,59 @@ public class ElasticsearchStringQueryUnitTests {
Method method = SampleRepository.class.getMethod(name, parameters);
return new ElasticsearchQueryMethod(method, new DefaultRepositoryMetadata(SampleRepository.class),
new SpelAwareProxyProjectionFactory(), converter.getMappingContext());
new SpelAwareProxyProjectionFactory(), operations.getElasticsearchConverter().getMappingContext());
}
private interface SampleRepository extends Repository<Person, String> {
@Query("{ 'bool' : { 'must' : { 'term' : { 'age' : ?0 } } } }")
List<Person> findByAge(Integer age);
@Query("{ 'bool' : { 'must' : { 'term' : { 'age' : ?0 } } } }")
List<Person> findByAgeIn(ArrayList<Integer> age);
@Query("{ 'bool' : { 'must' : { 'term' : { 'name' : '?0' } } } }")
Person findByName(String name);
@Query("{ 'bool' : { 'must' : { 'terms' : { 'name' : ?0 } } } }")
Person findByNameIn(ArrayList<String> names);
@Query(value = "name:(?0, ?11, ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?0, ?1)")
Person findWithRepeatedPlaceholder(String arg0, String arg1, String arg2, String arg3, String arg4, String arg5,
String arg6, String arg7, String arg8, String arg9, String arg10, String arg11);
@Query("{\"bool\":{\"must\": [{\"match\": {\"prefix\": {\"name\" : \"?0\"}}]}}")
SearchHits<Book> findByPrefix(String prefix);
@Query("{ 'bool' : { 'must' : { 'term' : { 'car' : '?0' } } } }")
Person findByCar(Car car);
}
/**
* @author Rizwan Idrees
* @author Mohsin Husen
* @author Artur Konczak
* @author Niklas Herder
*/
@Document(indexName = "test-index-person-query-unittest")
static class Person {
@Nullable public int age;
@Nullable @Id private String id;
@Nullable private String name;
@Nullable @Field(type = FieldType.Nested) private List<Car> car;
@Nullable @Field(type = FieldType.Nested, includeInParent = true) private List<Book> books;
@Nullable
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Nullable
public String getId() {
return id;
@@ -234,29 +307,6 @@ public class ElasticsearchStringQueryUnitTests {
}
}
static class Car {
@Nullable private String name;
@Nullable private String model;
@Nullable
public String getName() {
return name;
}
public void setName(@Nullable String name) {
this.name = name;
}
@Nullable
public String getModel() {
return model;
}
public void setModel(@Nullable String model) {
this.model = model;
}
}
static class Author {
@Nullable private String id;
@@ -280,5 +330,4 @@ public class ElasticsearchStringQueryUnitTests {
this.name = name;
}
}
}
@@ -16,6 +16,7 @@
package org.springframework.data.elasticsearch.repository.query;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -43,9 +44,6 @@ import org.springframework.data.elasticsearch.annotations.MultiField;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.core.query.StringQuery;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.Repository;
@@ -59,16 +57,15 @@ import org.springframework.lang.Nullable;
* @author Peter-Josef Meisch
*/
@ExtendWith(MockitoExtension.class)
public class ReactiveElasticsearchStringQueryUnitTests {
public class ReactiveElasticsearchStringQueryUnitTests extends ElasticsearchStringQueryUnitTestBase {
SpelExpressionParser PARSER = new SpelExpressionParser();
ElasticsearchConverter converter;
@Mock ReactiveElasticsearchOperations operations;
@BeforeEach
public void setUp() {
converter = new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext());
when(operations.getElasticsearchConverter()).thenReturn(setupConverter());
}
@Test // DATAES-519
@@ -132,7 +129,22 @@ public class ReactiveElasticsearchStringQueryUnitTests {
.isEqualTo("{\"bool\":{\"must\": [{\"match\": {\"prefix\": {\"name\" : \"hello \\\"Stranger\\\"\"}}]}}");
}
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, String... args)
@Test // #1866
@DisplayName("should use converter on parameters")
void shouldUseConverterOnParameters() throws Exception {
Car car = new Car();
car.setName("Toyota");
car.setModel("Prius");
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByCar", car);
assertThat(query).isInstanceOf(StringQuery.class);
assertThat(((StringQuery) query).getSource())
.isEqualTo("{ 'bool' : { 'must' : { 'term' : { 'car' : 'Toyota-Prius' } } } }");
}
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, Object... args)
throws NoSuchMethodException {
Class<?>[] argTypes = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);
@@ -152,7 +164,7 @@ public class ReactiveElasticsearchStringQueryUnitTests {
Method method = SampleRepository.class.getMethod(name, parameters);
return new ReactiveElasticsearchQueryMethod(method, new DefaultRepositoryMetadata(SampleRepository.class),
new SpelAwareProxyProjectionFactory(), converter.getMappingContext());
new SpelAwareProxyProjectionFactory(), operations.getElasticsearchConverter().getMappingContext());
}
private ReactiveElasticsearchStringQuery createQueryForMethod(String name, Class<?>... parameters) throws Exception {
@@ -180,6 +192,9 @@ public class ReactiveElasticsearchStringQueryUnitTests {
@Query("{\"bool\":{\"must\": [{\"match\": {\"prefix\": {\"name\" : \"?0\"}}]}}")
Flux<SearchHit<Book>> findByPrefix(String prefix);
@Query("{ 'bool' : { 'must' : { 'term' : { 'car' : '?0' } } } }")
Mono<Person> findByCar(Car car);
}
/**
@@ -292,29 +307,6 @@ public class ReactiveElasticsearchStringQueryUnitTests {
}
}
static class Car {
@Nullable private String name;
@Nullable private String model;
@Nullable
public String getName() {
return name;
}
public void setName(@Nullable String name) {
this.name = name;
}
@Nullable
public String getModel() {
return model;
}
public void setModel(@Nullable String model) {
this.model = model;
}
}
static class Author {
@Nullable private String id;
@@ -28,6 +28,7 @@ import java.lang.Long;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.elasticsearch.ElasticsearchStatusException;
@@ -541,14 +542,36 @@ class SimpleReactiveElasticsearchRepositoryTests {
@Test // DATAES-519
void annotatedFinderMethodShouldBeExecutedCorrectly() {
bulkIndex(new SampleEntity("id-one", "message"), //
new SampleEntity("id-two", "test message"), //
new SampleEntity("id-three", "test test")) //
.block();
int count = 30;
SampleEntity[] sampleEntities = IntStream.range(1, count + 1)
.mapToObj(i -> new SampleEntity("id-" + i, "test " + i)).collect(Collectors.toList())
.toArray(new SampleEntity[count]);
bulkIndex(sampleEntities).block();
repository.findAllViaAnnotatedQueryByMessageLike("test") //
.as(StepVerifier::create) //
.expectNextCount(2) //
.expectNextCount(count) //
.verifyComplete();
}
@Test // #1917
void annotatedFinderMethodPagedShouldBeExecutedCorrectly() {
int count = 30;
SampleEntity[] sampleEntities = IntStream.range(1, count + 1)
.mapToObj(i -> new SampleEntity("id-" + i, "test " + i)).collect(Collectors.toList())
.toArray(new SampleEntity[count]);
bulkIndex(sampleEntities).block();
repository.findAllViaAnnotatedQueryByMessageLikePaged("test", PageRequest.of(0, 20)) //
.as(StepVerifier::create) //
.expectNextCount(20) //
.verifyComplete();
repository.findAllViaAnnotatedQueryByMessageLikePaged("test", PageRequest.of(1, 20)) //
.as(StepVerifier::create) //
.expectNextCount(10) //
.verifyComplete();
}
@@ -596,6 +619,9 @@ class SimpleReactiveElasticsearchRepositoryTests {
@Query("{ \"bool\" : { \"must\" : { \"term\" : { \"message\" : \"?0\" } } } }")
Flux<SampleEntity> findAllViaAnnotatedQueryByMessageLike(String message);
@Query("{ \"bool\" : { \"must\" : { \"term\" : { \"message\" : \"?0\" } } } }")
Flux<SampleEntity> findAllViaAnnotatedQueryByMessageLikePaged(String message, Pageable pageable);
Mono<SampleEntity> findFirstByMessageLike(String message);
Mono<Long> countAllByMessage(String message);