Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0b3ecf6b23 | |||
| b96b5c2322 | |||
| 2a646e583d | |||
| 09c76b4694 | |||
| 1b59b31a72 | |||
| 2aba7a57fb | |||
| 15ca49a92e | |||
| b7088f8002 | |||
| 76f7ed5196 | |||
| e5445cf56f | |||
| 09a4e59e8d | |||
| 1e33e0f498 | |||
| e4df537382 | |||
| c1ab4d66e0 | |||
| 42cbab7ef6 | |||
| 9eed498fab | |||
| f16f70ff0f | |||
| 7494d344c5 | |||
| ca61901c1c | |||
| 323ccc9729 | |||
| d2960d764f | |||
| 8bb0a60450 | |||
| e33fe4d9fd | |||
| 0fd1b96ef3 | |||
| 30bc91c753 | |||
| 92806d2e11 | |||
| 2dd0a6771f | |||
| 79e0260f48 | |||
| 8d79a3efcf | |||
| d785c6c33c | |||
| c89368ce42 | |||
| c0781efbaa | |||
| d371404f90 | |||
| cc5b4fa635 | |||
| deae205fd4 | |||
| 796a5ebe34 | |||
| 2c63ba4097 | |||
| fe255c1bdc | |||
| 6f89e17451 | |||
| 0ad4fcb2eb | |||
| 4c3281f1eb | |||
| 303438ae63 | |||
| 254948d1c9 | |||
| 0bb239a674 | |||
| 3336ceade8 | |||
| e7398df948 |
+117
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
BIN
Binary file not shown.
+3
-1
@@ -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
|
||||
#Fri Sep 10 15:39:43 CEST 2021
|
||||
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.2/apache-maven-3.8.2-bin.zip
|
||||
|
||||
@@ -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" \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>4.2.2</version>
|
||||
<version>4.2.8</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>2.5.2</version>
|
||||
<version>2.5.8</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.8</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>
|
||||
|
||||
+12
-2
@@ -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());
|
||||
|
||||
+2
-1
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
|
||||
+3
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
+7
-5
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-9
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+67
-21
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data Elasticsearch 4.2.2 (2021.0.2)
|
||||
Spring Data Elasticsearch 4.2.8 (2021.0.8)
|
||||
Copyright (c) [2013-2021] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
@@ -22,6 +22,12 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+64
-3
@@ -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
|
||||
}
|
||||
|
||||
+211
-70
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -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")
|
||||
|
||||
+28
-11
@@ -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);
|
||||
}
|
||||
|
||||
+78
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+81
-32
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+23
-31
@@ -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;
|
||||
|
||||
+31
-5
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user