format = {}
to disable built-in date formats in the {@link Field} annotation. If you want to use only a
+ * custom date format pattern, you must set the format
property to empty {}
.
*
* @author Jakub Vavrik
* @author Tim te Beek
@@ -26,19 +28,6 @@
* @author Sascha Woo
*/
public enum DateFormat {
- /**
- * @deprecated since 4.2, will be removed in a future version. Use format = {}
to disable built-in date
- * formats in the @Field annotation.
- */
- @Deprecated
- none(""), //
- /**
- * @deprecated since 4.2, will be removed in a future version.It is no longer required for using a custom date format
- * pattern. If you want to use only a custom date format pattern, you must set the format
- * property to empty {}
.
- */
- @Deprecated
- custom(""), //
basic_date("uuuuMMdd"), //
basic_date_time("uuuuMMdd'T'HHmmss.SSSXXX"), //
basic_date_time_no_millis("uuuuMMdd'T'HHmmssXXX"), //
@@ -50,40 +39,173 @@ public enum DateFormat {
basic_t_time("'T'HHmmss.SSSXXX"), //
basic_t_time_no_millis("'T'HHmmssXXX"), //
basic_week_date("YYYY'W'wwe"), // week-based-year!
+ /**
+ * @since 5.3
+ */
+ strict_basic_week_date("YYYY'W'wwe"), // week-based-year!
basic_week_date_time("YYYY'W'wwe'T'HHmmss.SSSX"), // here Elasticsearch uses a different zone format
+ /**
+ * @since 5.3
+ */
+ strict_basic_week_date_time("YYYY'W'wwe'T'HHmmss.SSSX"), // here Elasticsearch uses a different zone format
basic_week_date_time_no_millis("YYYY'W'wwe'T'HHmmssX"), //
+ /**
+ * @since 5.3
+ */
+ strict_basic_week_date_time_no_millis("YYYY'W'wwe'T'HHmmssX"), //
date("uuuu-MM-dd"), //
+ /**
+ * @since 5.3
+ */
+ strict_date("uuuu-MM-dd"), //
date_hour("uuuu-MM-dd'T'HH"), //
+ /**
+ * @since 5.3
+ */
+ strict_date_hour("uuuu-MM-dd'T'HH"), //
date_hour_minute("uuuu-MM-dd'T'HH:mm"), //
+ /**
+ * @since 5.3
+ */
+ strict_date_hour_minute("uuuu-MM-dd'T'HH:mm"), //
date_hour_minute_second("uuuu-MM-dd'T'HH:mm:ss"), //
+ /**
+ * @since 5.3
+ */
+ strict_date_hour_minute_second("uuuu-MM-dd'T'HH:mm:ss"), //
date_hour_minute_second_fraction("uuuu-MM-dd'T'HH:mm:ss.SSS"), //
+ /**
+ * @since 5.3
+ */
+ strict_date_hour_minute_second_fraction("uuuu-MM-dd'T'HH:mm:ss.SSS"), //
date_hour_minute_second_millis("uuuu-MM-dd'T'HH:mm:ss.SSS"), //
+ /**
+ * @since 5.3
+ */
+ strict_date_hour_minute_second_millis("uuuu-MM-dd'T'HH:mm:ss.SSS"), //
date_optional_time("uuuu-MM-dd['T'HH:mm:ss.SSSXXX]"), //
+ /**
+ * @since 5.3
+ */
+ strict_date_optional_time("uuuu-MM-dd['T'HH:mm:ss.SSSXXX]"), //
+ strict_date_optional_time_nanos("uuuu-MM-dd['T'HH:mm:ss.SSSSSSXXX]"), //
date_time("uuuu-MM-dd'T'HH:mm:ss.SSSXXX"), //
- date_time_no_millis("uuuu-MM-dd'T'HH:mm:ssVV"), // here Elasticsearch uses the zone-id in it's implementation
+ /**
+ * @since 5.3
+ */
+ strict_date_time("uuuu-MM-dd'T'HH:mm:ss.SSSXXX"), //
+ date_time_no_millis("uuuu-MM-dd'T'HH:mm:ssVV"), // here Elasticsearch uses the zone-id in its implementation
+ /**
+ * @since 5.3
+ */
+ strict_date_time_no_millis("uuuu-MM-dd'T'HH:mm:ssVV"), // here Elasticsearch uses the zone-id in its implementation
epoch_millis("epoch_millis"), //
epoch_second("epoch_second"), //
hour("HH"), //
+ /**
+ * @since 5.3
+ */
+ strict_hour("HH"), //
hour_minute("HH:mm"), //
+ /**
+ * @since 5.3
+ */
+ strict_hour_minute("HH:mm"), //
hour_minute_second("HH:mm:ss"), //
+ /**
+ * @since 5.3
+ */
+ strict_hour_minute_second("HH:mm:ss"), //
hour_minute_second_fraction("HH:mm:ss.SSS"), //
+ /**
+ * @since 5.3
+ */
+ strict_hour_minute_second_fraction("HH:mm:ss.SSS"), //
hour_minute_second_millis("HH:mm:ss.SSS"), //
+ /**
+ * @since 5.3
+ */
+ strict_hour_minute_second_millis("HH:mm:ss.SSS"), //
ordinal_date("uuuu-DDD"), //
+ /**
+ * @since 5.3
+ */
+ strict_ordinal_date("uuuu-DDD"), //
ordinal_date_time("uuuu-DDD'T'HH:mm:ss.SSSXXX"), //
+ /**
+ * @since 5.3
+ */
+ strict_ordinal_date_time("uuuu-DDD'T'HH:mm:ss.SSSXXX"), //
ordinal_date_time_no_millis("uuuu-DDD'T'HH:mm:ssXXX"), //
+ /**
+ * @since 5.3
+ */
+ strict_ordinal_date_time_no_millis("uuuu-DDD'T'HH:mm:ssXXX"), //
time("HH:mm:ss.SSSXXX"), //
+ /**
+ * @since 5.3
+ */
+ strict_time("HH:mm:ss.SSSXXX"), //
time_no_millis("HH:mm:ssXXX"), //
+ /**
+ * @since 5.3
+ */
+ strict_time_no_millis("HH:mm:ssXXX"), //
t_time("'T'HH:mm:ss.SSSXXX"), //
+ /**
+ * @since 5.3
+ */
+ strict_t_time("'T'HH:mm:ss.SSSXXX"), //
t_time_no_millis("'T'HH:mm:ssXXX"), //
+ /**
+ * @since 5.3
+ */
+ strict_t_time_no_millis("'T'HH:mm:ssXXX"), //
week_date("YYYY-'W'ww-e"), //
+ /**
+ * @since 5.3
+ */
+ strict_week_date("YYYY-'W'ww-e"), //
week_date_time("YYYY-'W'ww-e'T'HH:mm:ss.SSSXXX"), //
+ /**
+ * @since 5.3
+ */
+ strict_week_date_time("YYYY-'W'ww-e'T'HH:mm:ss.SSSXXX"), //
week_date_time_no_millis("YYYY-'W'ww-e'T'HH:mm:ssXXX"), //
+ /**
+ * @since 5.3
+ */
+ strict_week_date_time_no_millis("YYYY-'W'ww-e'T'HH:mm:ssXXX"), //
weekyear(""), // no TemporalAccessor available for these 3
+ /**
+ * @since 5.3
+ */
+ strict_weekyear(""), // no TemporalAccessor available for these 3
weekyear_week(""), //
+ /**
+ * @since 5.3
+ */
+ strict_weekyear_week(""), //
weekyear_week_day(""), //
+ /**
+ * @since 5.3
+ */
+ strict_strict_weekyear_week_day(""), //
year("uuuu"), //
+ /**
+ * @since 5.3
+ */
+ strict_year("uuuu"), //
year_month("uuuu-MM"), //
- year_month_day("uuuu-MM-dd"); //
+ /**
+ * @since 5.3
+ */
+ strict_year_month("uuuu-MM"), //
+ year_month_day("uuuu-MM-dd"), //
+ /**
+ * @since 5.3
+ */
+ strict_year_month_day("uuuu-MM-dd"); //
private final String pattern;
diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/Document.java b/src/main/java/org/springframework/data/elasticsearch/annotations/Document.java
index 4378f0bdf7..1131b2cd59 100644
--- a/src/main/java/org/springframework/data/elasticsearch/annotations/Document.java
+++ b/src/main/java/org/springframework/data/elasticsearch/annotations/Document.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2021 the original author or authors.
+ * Copyright 2013-2025 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.
@@ -21,7 +21,6 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import org.elasticsearch.index.VersionType;
import org.springframework.data.annotation.Persistent;
/**
@@ -45,7 +44,7 @@
* Name of the Elasticsearch index.
*
- * √5 If not set, the name of the annotated property is used.
+ * The name to be used to store the field inside the document. If not set, the name of the annotated property
+ * is used.
*
* @since 3.2
*/
@@ -129,6 +130,10 @@
boolean norms() default true;
/**
+ * NOte that null_value setting are not supported in Elasticsearch for all types. For example setting a null_value on
+ * a field with type text will throw an exception in the server when the mapping is written to Elasticsearch. Alas,
+ * the Elasticsearch documentation does not specify on which types it is allowed on which it is not.
+ *
* @since 4.0
*/
String nullValue() default "";
@@ -141,7 +146,7 @@
/**
* @since 4.0
*/
- Similarity similarity() default Similarity.Default;
+ String similarity() default Similarity.Default;
/**
* @since 4.0
@@ -196,11 +201,55 @@
*/
int dims() default -1;
+ /**
+ * to be used in combination with {@link FieldType#Dense_Vector}
+ *
+ * @since 5.4
+ */
+ String elementType() default FieldElementType.DEFAULT;
+
+ /**
+ * to be used in combination with {@link FieldType#Dense_Vector}
+ *
+ * @since 5.4
+ */
+ KnnSimilarity knnSimilarity() default KnnSimilarity.DEFAULT;
+
+ /**
+ * to be used in combination with {@link FieldType#Dense_Vector}
+ *
+ * @since 5.4
+ */
+ KnnIndexOptions[] knnIndexOptions() default {};
+
/**
* Controls how Elasticsearch dynamically adds fields to the inner object within the document.
* To be used in combination with {@link FieldType#Object} or {@link FieldType#Nested}
- *
+ *
* @since 4.3
*/
Dynamic dynamic() default Dynamic.INHERIT;
+
+ /**
+ * marks this field to be excluded from the _source in Elasticsearch
+ * (https://www.elastic.co/guide/en/elasticsearch/reference/7.15/mapping-source-field.html#include-exclude)
+ *
+ * @since 4.3
+ */
+ boolean excludeFromSource() default false;
+
+ /**
+ * when this field is a {{@link String}}, a {{@link java.util.Collection}} or a {{@link java.util.Map}} that is empty
+ * this property controlls whether the empty value is sent to Elasticsearch.
+ *
+ * @since 5.1
+ */
+ boolean storeEmptyValue() default true;
+
+ /**
+ * overrides the field type in the mapping which otherwise will be taken from corresponding {@link FieldType}
+ *
+ * @since 5.4
+ */
+ String mappedTypeName() default "";
}
diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/DynamicMappingValue.java b/src/main/java/org/springframework/data/elasticsearch/annotations/FieldElementType.java
similarity index 65%
rename from src/main/java/org/springframework/data/elasticsearch/annotations/DynamicMappingValue.java
rename to src/main/java/org/springframework/data/elasticsearch/annotations/FieldElementType.java
index 85fe3b8e85..49271764ba 100644
--- a/src/main/java/org/springframework/data/elasticsearch/annotations/DynamicMappingValue.java
+++ b/src/main/java/org/springframework/data/elasticsearch/annotations/FieldElementType.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2021 the original author or authors.
+ * Copyright 2024-2025 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.
@@ -16,14 +16,11 @@
package org.springframework.data.elasticsearch.annotations;
/**
- * values for the {@link DynamicMapping annotation}
- *
- * @author Peter-Josef Meisch
- * @author Sascha Woo
- * @since 4.0
- * @deprecated since 4.3, use {@link Document#dynamic()} or {@link Field#dynamic()} instead.
+ * @author Haibo Liu
+ * @since 5.4
*/
-@Deprecated
-public enum DynamicMappingValue {
- True, False, Strict
+public final class FieldElementType {
+ public final static String DEFAULT = "";
+ public final static String FLOAT = "float";
+ public final static String BYTE = "byte";
}
diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/FieldType.java b/src/main/java/org/springframework/data/elasticsearch/annotations/FieldType.java
index 80c283841b..f701948d6d 100644
--- a/src/main/java/org/springframework/data/elasticsearch/annotations/FieldType.java
+++ b/src/main/java/org/springframework/data/elasticsearch/annotations/FieldType.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2021 the original author or authors.
+ * Copyright 2013-2025 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.
@@ -26,40 +26,75 @@
* @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"), //
+ /**
+ * @since 5.2
+ */
+ Constant_Keyword("constant_keyword"), //
+ /**
+ * @since 5.2
+ */
+ Alias("alias"), //
+ /**
+ * @since 5.2
+ */
+ Version("version"), //
+ /**
+ * @since 5.2
+ */
+ Murmur3("murmur3"), //
+ /**
+ * @since 5.2
+ */
+ Match_Only_Text("match_only_text"), //
+ /**
+ * @since 5.2
+ */
+ Annotated_Text("annotated_text") //
+ ;
+
+ private final String mappedName;
+
+ FieldType(String mappedName) {
+ this.mappedName = mappedName;
+ }
+
+ public String getMappedName() {
+ return mappedName;
+ }
}
diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/Filter.java b/src/main/java/org/springframework/data/elasticsearch/annotations/Filter.java
new file mode 100644
index 0000000000..7f07df55d1
--- /dev/null
+++ b/src/main/java/org/springframework/data/elasticsearch/annotations/Filter.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2024-2025 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.annotations;
+
+import org.springframework.core.annotation.AliasFor;
+
+/**
+ * Query used to limit documents.
+ *
+ * @author Youssef Aouichaoui
+ * @since 5.4
+ */
+public @interface Filter {
+ /**
+ * @return Query used to limit documents. Alias for {@link #query}.
+ */
+ @AliasFor("query")
+ String value() default "";
+
+ /**
+ * @return Query used to limit documents. Alias for {@link #value}.
+ */
+ @AliasFor("value")
+ String query() default "";
+}
diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/GeoPointField.java b/src/main/java/org/springframework/data/elasticsearch/annotations/GeoPointField.java
index b09e00cb16..05695abc98 100644
--- a/src/main/java/org/springframework/data/elasticsearch/annotations/GeoPointField.java
+++ b/src/main/java/org/springframework/data/elasticsearch/annotations/GeoPointField.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2021 the original author or authors.
+ * Copyright 2013-2025 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.
diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/GeoShapeField.java b/src/main/java/org/springframework/data/elasticsearch/annotations/GeoShapeField.java
index 2a170083c3..0121b07ee1 100644
--- a/src/main/java/org/springframework/data/elasticsearch/annotations/GeoShapeField.java
+++ b/src/main/java/org/springframework/data/elasticsearch/annotations/GeoShapeField.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2021 the original author or authors.
+ * Copyright 2017-2025 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.
diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/Highlight.java b/src/main/java/org/springframework/data/elasticsearch/annotations/Highlight.java
index ea6e49a6e4..30312ab434 100644
--- a/src/main/java/org/springframework/data/elasticsearch/annotations/Highlight.java
+++ b/src/main/java/org/springframework/data/elasticsearch/annotations/Highlight.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2020-2025 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.
diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/HighlightField.java b/src/main/java/org/springframework/data/elasticsearch/annotations/HighlightField.java
index 9c9dd48bbe..f6318be98a 100644
--- a/src/main/java/org/springframework/data/elasticsearch/annotations/HighlightField.java
+++ b/src/main/java/org/springframework/data/elasticsearch/annotations/HighlightField.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2020-2025 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.
diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/HighlightParameters.java b/src/main/java/org/springframework/data/elasticsearch/annotations/HighlightParameters.java
index 68c0b565a5..d4e8bbfd2b 100644
--- a/src/main/java/org/springframework/data/elasticsearch/annotations/HighlightParameters.java
+++ b/src/main/java/org/springframework/data/elasticsearch/annotations/HighlightParameters.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2020-2025 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.
@@ -21,6 +21,7 @@
/**
* @author Peter-Josef Meisch
+ * @author Haibo Liu
* @since 4.0
*/
@Documented
@@ -59,6 +60,8 @@
int numberOfFragments() default -1;
+ Query highlightQuery() default @Query;
+
String order() default "";
int phraseLimit() default -1;
diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/IndexOptions.java b/src/main/java/org/springframework/data/elasticsearch/annotations/IndexOptions.java
index 84aec8f3cd..2de226c7b1 100644
--- a/src/main/java/org/springframework/data/elasticsearch/annotations/IndexOptions.java
+++ b/src/main/java/org/springframework/data/elasticsearch/annotations/IndexOptions.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2021 the original author or authors.
+ * Copyright 2019-2025 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.
diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/IndexPrefixes.java b/src/main/java/org/springframework/data/elasticsearch/annotations/IndexPrefixes.java
index bc567573eb..01adc8fbb4 100644
--- a/src/main/java/org/springframework/data/elasticsearch/annotations/IndexPrefixes.java
+++ b/src/main/java/org/springframework/data/elasticsearch/annotations/IndexPrefixes.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2021 the original author or authors.
+ * Copyright 2019-2025 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.
diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/IndexedIndexName.java b/src/main/java/org/springframework/data/elasticsearch/annotations/IndexedIndexName.java
new file mode 100644
index 0000000000..4d76b97492
--- /dev/null
+++ b/src/main/java/org/springframework/data/elasticsearch/annotations/IndexedIndexName.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023-2025 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.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to mark a String property of an entity to be filled with the name of the index where the entity was stored
+ * after it is indexed into Elasticsearch. This can be used when the name of the index is dynamically created or when a
+ * document was indexed into a write alias.
+ *
+ * This can not be used to specify the index where an entity should be written to. + * + * @author Peter-Josef Meisch + * @since 5.1 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE }) +@Documented +@Field(type = FieldType.Auto) // prevents the property being written to the index mapping +public @interface IndexedIndexName { +} diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/InnerField.java b/src/main/java/org/springframework/data/elasticsearch/annotations/InnerField.java index 8ba0dca618..651bf5a825 100644 --- a/src/main/java/org/springframework/data/elasticsearch/annotations/InnerField.java +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/InnerField.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2021 the original author or authors. + * Copyright 2014-2025 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. @@ -29,6 +29,8 @@ * @author Aleksei Arsenev * @author Brian Kimmig * @author Morgan Lutz + * @author Haibo Liu + * @author Andriy Redko */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) @@ -109,7 +111,7 @@ /** * @since 4.0 */ - Similarity similarity() default Similarity.Default; + String similarity() default Similarity.Default; /** * @since 4.0 @@ -128,7 +130,7 @@ /** * to be used in combination with {@link FieldType#Rank_Feature} - * + * * @since 4.1 */ boolean positiveScoreImpact() default true; @@ -149,4 +151,32 @@ * @since 4.2 */ int dims() default -1; + + /** + * to be used in combination with {@link FieldType#Dense_Vector} + * + * @since 5.4 + */ + String elementType() default FieldElementType.DEFAULT; + + /** + * to be used in combination with {@link FieldType#Dense_Vector} + * + * @since 5.4 + */ + KnnSimilarity knnSimilarity() default KnnSimilarity.DEFAULT; + + /** + * to be used in combination with {@link FieldType#Dense_Vector} + * + * @since 5.4 + */ + KnnIndexOptions[] knnIndexOptions() default {}; + + /** + * overrides the field type in the mapping which otherwise will be taken from corresponding {@link FieldType} + * + * @since 5.4 + */ + String mappedTypeName() default ""; } diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/JoinTypeRelation.java b/src/main/java/org/springframework/data/elasticsearch/annotations/JoinTypeRelation.java index c3c3c960f7..eb2e1e4623 100644 --- a/src/main/java/org/springframework/data/elasticsearch/annotations/JoinTypeRelation.java +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/JoinTypeRelation.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 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. diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/JoinTypeRelations.java b/src/main/java/org/springframework/data/elasticsearch/annotations/JoinTypeRelations.java index 1f556b3a76..2004200cf2 100644 --- a/src/main/java/org/springframework/data/elasticsearch/annotations/JoinTypeRelations.java +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/JoinTypeRelations.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 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. diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/KnnAlgorithmType.java b/src/main/java/org/springframework/data/elasticsearch/annotations/KnnAlgorithmType.java new file mode 100644 index 0000000000..6110e54be8 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/KnnAlgorithmType.java @@ -0,0 +1,38 @@ +/* + * Copyright 2024-2025 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.annotations; + +/** + * @author Haibo Liu + * @since 5.4 + */ +public enum KnnAlgorithmType { + HNSW("hnsw"), + INT8_HNSW("int8_hnsw"), + FLAT("flat"), + INT8_FLAT("int8_flat"), + DEFAULT(""); + + private final String type; + + KnnAlgorithmType(String type) { + this.type = type; + } + + public String getType() { + return type; + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/KnnIndexOptions.java b/src/main/java/org/springframework/data/elasticsearch/annotations/KnnIndexOptions.java new file mode 100644 index 0000000000..56d871d3b5 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/KnnIndexOptions.java @@ -0,0 +1,40 @@ +/* + * Copyright 2024-2025 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.annotations; + +/** + * @author Haibo Liu + * @since 5.4 + */ +public @interface KnnIndexOptions { + + KnnAlgorithmType type() default KnnAlgorithmType.DEFAULT; + + /** + * Only applicable to {@link KnnAlgorithmType#HNSW} and {@link KnnAlgorithmType#INT8_HNSW} index types. + */ + int m() default -1; + + /** + * Only applicable to {@link KnnAlgorithmType#HNSW} and {@link KnnAlgorithmType#INT8_HNSW} index types. + */ + int efConstruction() default -1; + + /** + * Only applicable to {@link KnnAlgorithmType#INT8_HNSW} and {@link KnnAlgorithmType#INT8_FLAT} index types. + */ + float confidenceInterval() default -1F; +} diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/KnnSimilarity.java b/src/main/java/org/springframework/data/elasticsearch/annotations/KnnSimilarity.java new file mode 100644 index 0000000000..d03c42a6fd --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/KnnSimilarity.java @@ -0,0 +1,38 @@ +/* + * Copyright 2024-2025 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.annotations; + +/** + * @author Haibo Liu + * @since 5.4 + */ +public enum KnnSimilarity { + L2_NORM("l2_norm"), + DOT_PRODUCT("dot_product"), + COSINE("cosine"), + MAX_INNER_PRODUCT("max_inner_product"), + DEFAULT(""); + + private final String similarity; + + KnnSimilarity(String similarity) { + this.similarity = similarity; + } + + public String getSimilarity() { + return similarity; + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/Mapping.java b/src/main/java/org/springframework/data/elasticsearch/annotations/Mapping.java index d2827e55bf..c2d48c3884 100644 --- a/src/main/java/org/springframework/data/elasticsearch/annotations/Mapping.java +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/Mapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2021 the original author or authors. + * Copyright 2014-2025 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. @@ -74,7 +74,14 @@ */ String runtimeFieldsPath() default ""; + /** + * field alias definitions to be written to the index mapping + * + * @since 5.3 + */ + MappingAlias[] aliases() default {}; + enum Detection { - DEFAULT, TRUE, FALSE; + DEFAULT, TRUE, FALSE } } diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/DynamicMapping.java b/src/main/java/org/springframework/data/elasticsearch/annotations/MappingAlias.java similarity index 64% rename from src/main/java/org/springframework/data/elasticsearch/annotations/DynamicMapping.java rename to src/main/java/org/springframework/data/elasticsearch/annotations/MappingAlias.java index 513faf7a51..791659e9d5 100644 --- a/src/main/java/org/springframework/data/elasticsearch/annotations/DynamicMapping.java +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/MappingAlias.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2024-2025 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. @@ -17,24 +17,29 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Annotation to set the dynamic mapping mode - * {@see elasticsearch doc} - * + * Defines a field alias in the index mapping. + * * @author Peter-Josef Meisch - * @author Sascha Woo - * @since 4.0 - * @deprecated since 4.3, use {@link Document#dynamic()} or {@link Field#dynamic()} instead. + * @since 5.3 */ @Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.TYPE, ElementType.FIELD }) +@Target(ElementType.FIELD) @Documented -@Deprecated -public @interface DynamicMapping { +@Inherited +public @interface MappingAlias { + /** + * the name of the alias. + */ + String name(); - DynamicMappingValue value() default DynamicMappingValue.True; + /** + * the path of the alias. + */ + String path(); } diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/MultiField.java b/src/main/java/org/springframework/data/elasticsearch/annotations/MultiField.java index c63558b806..9dff38c1f1 100644 --- a/src/main/java/org/springframework/data/elasticsearch/annotations/MultiField.java +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/MultiField.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2021 the original author or authors. + * Copyright 2014-2025 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. @@ -30,7 +30,7 @@ * @author Peter-Josef Meisch */ @Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE }) +@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.METHOD }) @Documented public @interface MultiField { diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/NullValueType.java b/src/main/java/org/springframework/data/elasticsearch/annotations/NullValueType.java index 08ae6ebfec..a131b12a8e 100644 --- a/src/main/java/org/springframework/data/elasticsearch/annotations/NullValueType.java +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/NullValueType.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-2025 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. diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/Query.java b/src/main/java/org/springframework/data/elasticsearch/annotations/Query.java index 3c14197d8d..9f1b755c35 100644 --- a/src/main/java/org/springframework/data/elasticsearch/annotations/Query.java +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/Query.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 the original author or authors. + * Copyright 2013-2025 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. @@ -15,7 +15,14 @@ */ package org.springframework.data.elasticsearch.annotations; -import java.lang.annotation.*; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.core.annotation.AliasFor; +import org.springframework.data.annotation.QueryAnnotation; /** * Query @@ -23,24 +30,27 @@ * @author Rizwan Idrees * @author Mohsin Husen * @author Peter-Josef Meisch + * @author Steven Pearce */ @Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) +@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE }) @Documented +@QueryAnnotation public @interface Query { /** - * @return Elasticsearch query to be used when executing query. May contain placeholders eg. ?0 + * @return Elasticsearch query to be used when executing query. May contain placeholders eg. ?0. Alias for query. */ + @AliasFor("query") String value() default ""; /** - * Named Query Named looked up by repository. - * - * @deprecated since 4.2, not implemented and used anywhere + * @return Elasticsearch query to be used when executing query. May contain placeholders eg. ?0. Alias for value + * @since 5.0 */ - String name() default ""; + @AliasFor("value") + String query() default ""; /** * Returns whether the query defined should be executed as count projection. @@ -50,4 +60,3 @@ */ boolean count() default false; } - diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/ScriptedField.java b/src/main/java/org/springframework/data/elasticsearch/annotations/ScriptedField.java index f1eb3e06a3..cc596c54f3 100644 --- a/src/main/java/org/springframework/data/elasticsearch/annotations/ScriptedField.java +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/ScriptedField.java @@ -3,6 +3,7 @@ import java.lang.annotation.*; /** + * Marks a property to be populated with the result of a scripted field retrieved from an Elasticsearch response. * @author Ryan Murfitt */ @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/SearchTemplateQuery.java b/src/main/java/org/springframework/data/elasticsearch/annotations/SearchTemplateQuery.java new file mode 100644 index 0000000000..f50675d979 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/SearchTemplateQuery.java @@ -0,0 +1,42 @@ +/* + * Copyright 2025 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.annotations; + +import org.springframework.data.annotation.QueryAnnotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to mark a repository method as a search template method. The annotation defines the search template id, + * the parameters for the search template are taken from the method's arguments. + * + * @author P.J. Meisch (pj.meisch@sothawo.com) + * @since 5.5 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE }) +@Documented +@QueryAnnotation +public @interface SearchTemplateQuery { + /** + * The id of the search template. Must not be empt or null. + */ + String id(); +} diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/Setting.java b/src/main/java/org/springframework/data/elasticsearch/annotations/Setting.java index c2b836d346..926154f1f2 100644 --- a/src/main/java/org/springframework/data/elasticsearch/annotations/Setting.java +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/Setting.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2021 the original author or authors. + * Copyright 2014-2025 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. diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/Similarity.java b/src/main/java/org/springframework/data/elasticsearch/annotations/Similarity.java index f2cc856339..46cafd91a2 100644 --- a/src/main/java/org/springframework/data/elasticsearch/annotations/Similarity.java +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/Similarity.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2019-2025 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. @@ -19,18 +19,9 @@ * @author Peter-Josef Meisch * @since 4.0 */ -public enum Similarity { - Default("default"), BM25("BM25"), classic("classic"), Boolean("boolean"); - - // need to use a custom name because 'boolean' can't be used as enum name - private final String toStringName; - - Similarity(String name) { - this.toStringName = name; - } - - @Override - public String toString() { - return toStringName; - } +public final class Similarity { + public final static String Default = "default"; + public final static String BM25 = "BM25"; + public final static String classic = "classic"; + public final static String Boolean = "boolean"; } diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/SourceFilters.java b/src/main/java/org/springframework/data/elasticsearch/annotations/SourceFilters.java new file mode 100644 index 0000000000..055ecc616f --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/SourceFilters.java @@ -0,0 +1,73 @@ +/* + * Copyright 2022-2025 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.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This annotation can be placed on repository methods to define the properties that should be requested from + * Elasticsearch when the method is run. + * + * @author Alexander Torres + * @author Peter-Josef Meisch + * @since 5.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE }) +@Documented +public @interface SourceFilters { + + /** + * Properties to be requested from Elasticsearch to be included in the response. These can be passed in as literals + * like + * + *
+ * {@code @SourceFilters(includes = {"property1", "property2"})} + *+ * + * or as a parameterized value + * + *
+ * {@code @SourceFilters(includes = "?0")} + *+ * + * when the list of properties is passed as a function parameter. + */ + String[] includes() default ""; + + /** + * Properties to be requested from Elasticsearch to be excluded in the response. These can be passed in as literals + * like + * + *
+ * {@code @SourceFilters(excludes = {"property1", "property2"})} + *+ * + * or as a parameterized value + * + *
+ * {@code @SourceFilters(excludes = "?0")} + *+ * + * when the list of properties is passed as a function parameter. + */ + String[] excludes() default ""; +} diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/TermVector.java b/src/main/java/org/springframework/data/elasticsearch/annotations/TermVector.java index 317268c962..25de2cbcad 100644 --- a/src/main/java/org/springframework/data/elasticsearch/annotations/TermVector.java +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/TermVector.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2019-2025 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. diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/ValueConverter.java b/src/main/java/org/springframework/data/elasticsearch/annotations/ValueConverter.java new file mode 100644 index 0000000000..eb848bfed2 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/ValueConverter.java @@ -0,0 +1,48 @@ +/* + * Copyright 2021-2025 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.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter; + +/** + * Annotation to put on a property of an entity to define a value converter which can convert the property to a type + * that Elasticsearch understands and back. + * + * @author Peter-Josef Meisch + * @since 4.3 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE }) +@Documented +@Inherited +public @interface ValueConverter { + + /** + * Defines the class implementing the {@link PropertyValueConverter} interface. If this is a normal class, it must + * provide a default constructor with no arguments. If this is an enum and thus implementing a singleton by enum it + * must only have one enum value. + * + * @return the class to use for conversion + */ + Class extends PropertyValueConverter> value(); +} diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/WriteOnlyProperty.java b/src/main/java/org/springframework/data/elasticsearch/annotations/WriteOnlyProperty.java new file mode 100644 index 0000000000..7704450e26 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/WriteOnlyProperty.java @@ -0,0 +1,35 @@ +/* + * Copyright 2022-2025 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.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to mark a property that will be written to Elasticsearch, but not set when reading from Elasticsearch. + * This is needed for synthesized fields that may be used for search but that are not available in the entity. + * + * @author Peter-Josef Meisch + * @since 5.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.FIELD }) +@Documented +public @interface WriteOnlyProperty { +} diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/WriteTypeHint.java b/src/main/java/org/springframework/data/elasticsearch/annotations/WriteTypeHint.java index 0aae5f9f7b..86a844cc18 100644 --- a/src/main/java/org/springframework/data/elasticsearch/annotations/WriteTypeHint.java +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/WriteTypeHint.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 the original author or authors. + * Copyright 2021-2025 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. diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/package-info.java b/src/main/java/org/springframework/data/elasticsearch/annotations/package-info.java index 60fe252678..4b8ccdf64e 100644 --- a/src/main/java/org/springframework/data/elasticsearch/annotations/package-info.java +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/package-info.java @@ -1,3 +1,2 @@ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields +@org.jspecify.annotations.NullMarked package org.springframework.data.elasticsearch.annotations; diff --git a/src/main/java/org/springframework/data/elasticsearch/aot/ElasticsearchAotPredicates.java b/src/main/java/org/springframework/data/elasticsearch/aot/ElasticsearchAotPredicates.java new file mode 100644 index 0000000000..c3921b8940 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/aot/ElasticsearchAotPredicates.java @@ -0,0 +1,35 @@ +/* + * Copyright 2023-2025 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.aot; + +import java.util.function.Predicate; + +import org.springframework.data.util.ReactiveWrappers; + +/** + * @author Peter-Josef Meisch + * @since 5.1 + */ +public class ElasticsearchAotPredicates { + + public static final Predicate
* // "localhost:9200" @@ -68,9 +64,8 @@ static ClientConfiguration localhost() { } /** - * Creates a new {@link ClientConfiguration} instance configured to a single host given {@code hostAndPort}. - * - * For example given the endpoint http://localhost:9200 + * Creates a new {@link ClientConfiguration} instance configured to a single host given {@code hostAndPort}. For + * example given the endpoint http://localhost:9200 * ** ClientConfiguration configuration = ClientConfiguration.create("localhost:9200"); @@ -83,9 +78,8 @@ static ClientConfiguration create(String hostAndPort) { } /** - * Creates a new {@link ClientConfiguration} instance configured to a single host given {@link InetSocketAddress}. - * - * For example given the endpoint http://localhost:9200 + * Creates a new {@link ClientConfiguration} instance configured to a single host given {@link InetSocketAddress}. For + * example given the endpoint http://localhost:9200 * ** ClientConfiguration configuration = ClientConfiguration @@ -120,16 +114,22 @@ static ClientConfiguration create(InetSocketAddress socketAddress) { boolean useSsl(); /** - * Returns the {@link SSLContext} to use. Can be {@link Optional#empty()} if unconfigured. + * Returns the {@link SSLContext} to use. Can be {@link Optional#empty()} if not configured. * - * @return the {@link SSLContext} to use. Can be {@link Optional#empty()} if unconfigured. + * @return the {@link SSLContext} to use. Can be {@link Optional#empty()} if not configured. */ OptionalgetSslContext(); /** - * Returns the {@link HostnameVerifier} to use. Can be {@link Optional#empty()} if unconfigured. + * @return the optional SHA-256 fingerprint of the self-signed http_ca.crt certificate output by Elasticsearch at + * startup time. + */ + Optional getCaFingerprint(); + + /** + * Returns the {@link HostnameVerifier} to use. Can be {@link Optional#empty()} if not configured. * - * @return the {@link HostnameVerifier} to use. Can be {@link Optional#empty()} if unconfigured. + * @return the {@link HostnameVerifier} to use. Can be {@link Optional#empty()} if not configured. */ Optional getHostNameVerifier(); @@ -137,7 +137,6 @@ static ClientConfiguration create(InetSocketAddress socketAddress) { * Returns the {@link java.time.Duration connect timeout}. * * @see java.net.Socket#connect(SocketAddress, int) - * @see io.netty.channel.ChannelOption#CONNECT_TIMEOUT_MILLIS */ Duration getConnectTimeout(); @@ -145,14 +144,12 @@ static ClientConfiguration create(InetSocketAddress socketAddress) { * Returns the {@link java.time.Duration socket timeout} which is typically applied as SO-timeout/read timeout. * * @see java.net.Socket#setSoTimeout(int) - * @see io.netty.handler.timeout.ReadTimeoutHandler - * @see io.netty.handler.timeout.WriteTimeoutHandler */ Duration getSocketTimeout(); /** * Returns the path prefix that should be prepended to HTTP(s) requests for Elasticsearch behind a proxy. - * + * * @return the path prefix. * @since 4.0 */ @@ -161,22 +158,17 @@ static ClientConfiguration create(InetSocketAddress socketAddress) { /** * returns an optionally set proxy in the form host:port - * + * * @return the optional proxy * @since 4.0 */ Optional getProxy(); /** - * @return the function for configuring a WebClient. - */ - Function getWebClientConfigurer(); - - /** - * @return the client configuration callback. - * @since 4.2 + * @return the client configuration callbacks + * @since 4.3 */ - HttpClientConfigCallback getHttpClientConfigurer(); + List > getClientConfigurers(); /** * @return the supplier for custom headers. @@ -241,6 +233,15 @@ interface MaybeSecureClientConfigurationBuilder extends TerminalClientConfigurat */ TerminalClientConfigurationBuilder usingSsl(); + /** + * Connects using https if flag is true. + * + * @param flag whether to use https in the connection + * @return the {@link TerminalClientConfigurationBuilder} + * @since 5.3 + */ + TerminalClientConfigurationBuilder usingSsl(boolean flag); + /** * Connect via {@literal https} using the given {@link SSLContext}.
* NOTE You need to leave out the protocol in @@ -259,6 +260,15 @@ interface MaybeSecureClientConfigurationBuilder extends TerminalClientConfigurat * @return the {@link TerminalClientConfigurationBuilder}. */ TerminalClientConfigurationBuilder usingSsl(SSLContext sslContext, HostnameVerifier hostnameVerifier); + + /** + * Connect via https using a SSLContext that is build from the given certificate fingerprint. + * + * @param caFingerprint the SHA-256 fingerprint of the self-signed http_ca.crt certificate output by Elasticsearch + * at startup time. + * @return the {@link TerminalClientConfigurationBuilder}. + */ + TerminalClientConfigurationBuilder usingSsl(String caFingerprint); } /** @@ -274,7 +284,7 @@ interface TerminalClientConfigurationBuilder { TerminalClientConfigurationBuilder withDefaultHeaders(HttpHeaders defaultHeaders); /** - * Configure the {@literal milliseconds} for the connect timeout. + * Configure the {@literal milliseconds} for the connect-timeout. * * @param millis the timeout to use. * @return the {@link TerminalClientConfigurationBuilder} @@ -290,7 +300,6 @@ default TerminalClientConfigurationBuilder withConnectTimeout(long millis) { * @param timeout the timeout to use. Must not be {@literal null}. * @return the {@link TerminalClientConfigurationBuilder} * @see java.net.Socket#connect(SocketAddress, int) - * @see io.netty.channel.ChannelOption#CONNECT_TIMEOUT_MILLIS */ TerminalClientConfigurationBuilder withConnectTimeout(Duration timeout); @@ -311,8 +320,6 @@ default TerminalClientConfigurationBuilder withSocketTimeout(long millis) { * @param timeout the timeout to use. Must not be {@literal null}. * @return the {@link TerminalClientConfigurationBuilder} * @see java.net.Socket#setSoTimeout(int) - * @see io.netty.handler.timeout.ReadTimeoutHandler - * @see io.netty.handler.timeout.WriteTimeoutHandler */ TerminalClientConfigurationBuilder withSocketTimeout(Duration timeout); @@ -327,7 +334,7 @@ default TerminalClientConfigurationBuilder withSocketTimeout(long millis) { /** * Configure the path prefix that will be prepended to any HTTP(s) requests - * + * * @param pathPrefix the pathPrefix. * @return the {@link TerminalClientConfigurationBuilder} * @since 4.0 @@ -341,21 +348,13 @@ default TerminalClientConfigurationBuilder withSocketTimeout(long millis) { TerminalClientConfigurationBuilder withProxy(String proxy); /** - * set customization hook in case of a reactive configuration - * - * @param webClientConfigurer function to configure the WebClient - * @return the {@link TerminalClientConfigurationBuilder}. - */ - TerminalClientConfigurationBuilder withWebClientConfigurer(FunctionwebClientConfigurer); - - /** - * Register a {HttpClientConfigCallback} to configure the non-reactive REST client. - * - * @param httpClientConfigurer configuration callback, must not be null. + * Register a {@link ClientConfigurationCallback} to configure the client. + * + * @param clientConfigurer configuration callback, must not be {@literal null}. * @return the {@link TerminalClientConfigurationBuilder}. - * @since 4.2 + * @since 4.3 */ - TerminalClientConfigurationBuilder withHttpClientConfigurer(HttpClientConfigCallback httpClientConfigurer); + TerminalClientConfigurationBuilder withClientConfigurer(ClientConfigurationCallback> clientConfigurer); /** * set a supplier for custom headers. This is invoked for every HTTP request to Elasticsearch to retrieve headers @@ -377,4 +376,15 @@ default TerminalClientConfigurationBuilder withSocketTimeout(long millis) { */ ClientConfiguration build(); } + + /** + * Callback to be executed to configure a client. + * + * @param the type of the client configuration class. + * @since 4.3 + */ + @FunctionalInterface + interface ClientConfigurationCallback { + T configure(T clientConfigurer); + } } diff --git a/src/main/java/org/springframework/data/elasticsearch/client/ClientConfigurationBuilder.java b/src/main/java/org/springframework/data/elasticsearch/client/ClientConfigurationBuilder.java index 2f8be5b397..71af992127 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/ClientConfigurationBuilder.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/ClientConfigurationBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 the original author or authors. + * Copyright 2018-2025 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. @@ -20,21 +20,17 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.function.Function; import java.util.function.Supplier; -import java.util.stream.Collectors; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; -import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback; +import org.jspecify.annotations.Nullable; import org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationBuilderWithRequiredEndpoint; import org.springframework.data.elasticsearch.client.ClientConfiguration.MaybeSecureClientConfigurationBuilder; import org.springframework.data.elasticsearch.client.ClientConfiguration.TerminalClientConfigurationBuilder; -import org.springframework.http.HttpHeaders; -import org.springframework.lang.Nullable; +import org.springframework.data.elasticsearch.support.HttpHeaders; import org.springframework.util.Assert; -import org.springframework.web.reactive.function.client.WebClient; /** * Default builder implementation for {@link ClientConfiguration}. @@ -49,20 +45,20 @@ class ClientConfigurationBuilder implements ClientConfigurationBuilderWithRequiredEndpoint, MaybeSecureClientConfigurationBuilder { - private List hosts = new ArrayList<>(); - private HttpHeaders headers = HttpHeaders.EMPTY; + private final List hosts = new ArrayList<>(); + private HttpHeaders headers = new HttpHeaders(); private boolean useSsl; - private @Nullable SSLContext sslContext; - private @Nullable HostnameVerifier hostnameVerifier; + @Nullable private SSLContext sslContext; + @Nullable private String caFingerprint; + @Nullable private HostnameVerifier hostnameVerifier; private Duration connectTimeout = Duration.ofSeconds(10); private Duration soTimeout = Duration.ofSeconds(5); - private @Nullable String username; - private @Nullable String password; - private @Nullable String pathPrefix; - private @Nullable String proxy; - private Function webClientConfigurer = Function.identity(); - private Supplier headersSupplier = () -> HttpHeaders.EMPTY; - private HttpClientConfigCallback httpClientConfigurer = httpClientBuilder -> httpClientBuilder; + @Nullable private String username; + @Nullable private String password; + @Nullable private String pathPrefix; + @Nullable private String proxy; + private Supplier headersSupplier = HttpHeaders::new; + private final List > clientConfigurers = new ArrayList<>(); /* * (non-Javadoc) @@ -73,7 +69,7 @@ public MaybeSecureClientConfigurationBuilder connectedTo(String... hostAndPorts) Assert.notEmpty(hostAndPorts, "At least one host is required"); - this.hosts.addAll(Arrays.stream(hostAndPorts).map(ClientConfigurationBuilder::parse).collect(Collectors.toList())); + this.hosts.addAll(Arrays.stream(hostAndPorts).map(ClientConfigurationBuilder::parse).toList()); return this; } @@ -109,6 +105,13 @@ public TerminalClientConfigurationBuilder usingSsl() { return this; } + @Override + public TerminalClientConfigurationBuilder usingSsl(boolean flag) { + + this.useSsl = flag; + return this; + } + /* * (non-Javadoc) * @see org.springframework.data.elasticsearch.client.ClientConfiguration.MaybeSecureClientConfigurationBuilder#usingSsl(javax.net.ssl.SSLContext) @@ -139,10 +142,20 @@ public TerminalClientConfigurationBuilder usingSsl(SSLContext sslContext, Hostna return this; } + @Override + public TerminalClientConfigurationBuilder usingSsl(String caFingerprint) { + + Assert.notNull(caFingerprint, "caFingerprint must not be null"); + + this.useSsl = true; + this.caFingerprint = caFingerprint; + return this; + } + /* - * (non-Javadoc) - * @see org.springframework.data.elasticsearch.client.ClientConfiguration.TerminalClientConfigurationBuilder#withDefaultHeaders(org.springframework.http.HttpHeaders) - */ + * (non-Javadoc) + * @see org.springframework.data.elasticsearch.client.ClientConfiguration.TerminalClientConfigurationBuilder#withDefaultHeaders(org.springframework.http.HttpHeaders) + */ @Override public TerminalClientConfigurationBuilder withDefaultHeaders(HttpHeaders defaultHeaders) { @@ -200,21 +213,12 @@ public TerminalClientConfigurationBuilder withPathPrefix(String pathPrefix) { } @Override - public TerminalClientConfigurationBuilder withWebClientConfigurer( - Function webClientConfigurer) { + public TerminalClientConfigurationBuilder withClientConfigurer( + ClientConfiguration.ClientConfigurationCallback> clientConfigurer) { - Assert.notNull(webClientConfigurer, "webClientConfigurer must not be null"); + Assert.notNull(clientConfigurer, "clientConfigurer must not be null"); - this.webClientConfigurer = webClientConfigurer; - return this; - } - - @Override - public TerminalClientConfigurationBuilder withHttpClientConfigurer(HttpClientConfigCallback httpClientConfigurer) { - - Assert.notNull(httpClientConfigurer, "httpClientConfigurer must not be null"); - - this.httpClientConfigurer = httpClientConfigurer; + this.clientConfigurers.add(clientConfigurer); return this; } @@ -235,14 +239,15 @@ public TerminalClientConfigurationBuilder withHeaders(Supplier head public ClientConfiguration build() { if (username != null && password != null) { - if (HttpHeaders.EMPTY.equals(headers)) { - headers = new HttpHeaders(); - } headers.setBasicAuth(username, password); } - return new DefaultClientConfiguration(hosts, headers, useSsl, sslContext, soTimeout, connectTimeout, pathPrefix, - hostnameVerifier, proxy, webClientConfigurer, httpClientConfigurer, headersSupplier); + if (sslContext != null && caFingerprint != null) { + throw new IllegalArgumentException("Either SSLContext or caFingerprint must be set, but not both"); + } + + return new DefaultClientConfiguration(hosts, headers, useSsl, sslContext, caFingerprint, soTimeout, connectTimeout, + pathPrefix, hostnameVerifier, proxy, clientConfigurers, headersSupplier); } private static InetSocketAddress parse(String hostAndPort) { diff --git a/src/main/java/org/springframework/data/elasticsearch/client/ClientLogger.java b/src/main/java/org/springframework/data/elasticsearch/client/ClientLogger.java deleted file mode 100644 index 63100a3907..0000000000 --- a/src/main/java/org/springframework/data/elasticsearch/client/ClientLogger.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2018-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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.client; - -import java.util.function.Supplier; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; -import org.springframework.lang.Nullable; -import org.springframework.util.ObjectUtils; - -/** - * Logging Utility to log client requests and responses. Logs client requests and responses to Elasticsearch to a - * dedicated logger: {@code org.springframework.data.elasticsearch.client.WIRE} on {@link org.slf4j.event.Level#TRACE} - * level. - * - * @author Mark Paluch - * @author Christoph Strobl - * @since 3.2 - */ -public abstract class ClientLogger { - - private static final String lineSeparator = System.getProperty("line.separator"); - private static final Logger WIRE_LOGGER = LoggerFactory - .getLogger("org.springframework.data.elasticsearch.client.WIRE"); - - private ClientLogger() {} - - /** - * Returns {@literal true} if the logger is enabled. - * - * @return {@literal true} if the logger is enabled. - */ - public static boolean isEnabled() { - return WIRE_LOGGER.isTraceEnabled(); - } - - /** - * Log an outgoing HTTP request. - * - * @param logId the correlation Id, see {@link #newLogId()}. - * @param method HTTP method - * @param endpoint URI - * @param parameters optional parameters. - */ - public static void logRequest(String logId, String method, String endpoint, Object parameters) { - - if (isEnabled()) { - - WIRE_LOGGER.trace("[{}] Sending request {} {} with parameters: {}", logId, method.toUpperCase(), endpoint, - parameters); - } - } - - /** - * Log an outgoing HTTP request with a request body. - * - * @param logId the correlation Id, see {@link #newLogId()}. - * @param method HTTP method - * @param endpoint URI - * @param parameters optional parameters. - * @param body body content supplier. - */ - public static void logRequest(String logId, String method, String endpoint, Object parameters, - Supplier