Compare commits

...

12 Commits
main ... 4.3.1

Author SHA1 Message Date
Christoph Strobl
95762b4fde
Release version 4.3.1 (2021.1.1).
See #1987
2022-01-14 10:28:59 +01:00
Christoph Strobl
0771e90031
Prepare 4.3.1 (2021.1.1).
See #1987
2022-01-14 10:28:27 +01:00
Peter-Josef Meisch
6729330500
Update to log4j 2.17.0 2021-12-18 20:34:28 +01:00
Peter-Josef Meisch
8796292611
update log4j dependency version 2021-12-14 13:53:59 +01:00
Peter-Josef Meisch
f3f9ca4002
Fix FieldType mapping.
Original PullRequest #2026
Closes #2024

(cherry picked from commit f7a6a97c4e2fcde86fa182f599e548a75ce73865)
2021-12-13 21:52:28 +01:00
Peter-Josef Meisch
083a38ed57
Fix IndexOutOfBoundsException when try to map inner hits with no results returned.
Original Pull Request #1998
Closes #1997
Co-authored-by: Peter-Josef Meisch <pj.meisch@sothawo.com>

(cherry picked from commit 49324a369af627e390f981ed6b793f0f503526c7)
2021-12-05 09:02:06 +01:00
Sascha Woo
4f3aa52958
Fix IndexOutOfBoundsException when try to map inner hits with no results returned.
Original Pull Request #1998
Closes #1997
Co-authored-by: Peter-Josef Meisch <pj.meisch@sothawo.com>

(cherry picked from commit 49324a369af627e390f981ed6b793f0f503526c7)
2021-11-23 20:26:14 +01:00
Peter-Josef Meisch
3256a2bfe0
Fix RestStatusException cause.
Original Pull Request #1996
Closes #1995

(cherry picked from commit 45b4c99e951e4519c3fe1e2d4a51c8bd16ab33b0)
2021-11-16 07:38:01 +01:00
Peter-Josef Meisch
95401a5bd7
Exclude commons-logging dependency from Elasticsearch dependencies.
Original Pull Request #1993
Closes #1989
2021-11-13 14:56:57 +01:00
Mark Paluch
12cd64cfc8
Update build trigger to use branch build.
See #1965
2021-11-12 14:31:54 +01:00
Jens Schauder
7e557317d1
After release cleanups.
See #1965
2021-11-12 11:00:07 +01:00
Jens Schauder
c9846ab8ad
Prepare next development iteration.
See #1965
2021-11-12 11:00:05 +01:00
19 changed files with 570 additions and 199 deletions

2
Jenkinsfile vendored
View File

@ -3,7 +3,7 @@ pipeline {
triggers { triggers {
pollSCM 'H/10 * * * *' pollSCM 'H/10 * * * *'
upstream(upstreamProjects: "spring-data-commons/main", threshold: hudson.model.Result.SUCCESS) upstream(upstreamProjects: "spring-data-commons/2.6.x", threshold: hudson.model.Result.SUCCESS)
} }
options { options {

24
pom.xml
View File

@ -5,12 +5,12 @@
<groupId>org.springframework.data</groupId> <groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId> <artifactId>spring-data-elasticsearch</artifactId>
<version>4.3.0</version> <version>4.3.1</version>
<parent> <parent>
<groupId>org.springframework.data.build</groupId> <groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId> <artifactId>spring-data-parent</artifactId>
<version>2.6.0</version> <version>2.6.1</version>
</parent> </parent>
<name>Spring Data Elasticsearch</name> <name>Spring Data Elasticsearch</name>
@ -19,9 +19,9 @@
<properties> <properties>
<elasticsearch>7.15.2</elasticsearch> <elasticsearch>7.15.2</elasticsearch>
<log4j>2.14.1</log4j> <log4j>2.17.0</log4j>
<netty>4.1.65.Final</netty> <netty>4.1.65.Final</netty>
<springdata.commons>2.6.0</springdata.commons> <springdata.commons>2.6.1</springdata.commons>
<testcontainers>1.15.3</testcontainers> <testcontainers>1.15.3</testcontainers>
<blockhound-junit>1.0.6.RELEASE</blockhound-junit> <blockhound-junit>1.0.6.RELEASE</blockhound-junit>
<java-module-name>spring.data.elasticsearch</java-module-name> <java-module-name>spring.data.elasticsearch</java-module-name>
@ -145,6 +145,12 @@
<groupId>org.elasticsearch.client</groupId> <groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
<version>${elasticsearch}</version> <version>${elasticsearch}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
@ -152,6 +158,12 @@
<groupId>org.elasticsearch.plugin</groupId> <groupId>org.elasticsearch.plugin</groupId>
<artifactId>transport-netty4-client</artifactId> <artifactId>transport-netty4-client</artifactId>
<version>${elasticsearch}</version> <version>${elasticsearch}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
@ -461,7 +473,9 @@
</module> </module>
</checkstyleRules> </checkstyleRules>
<includes>**/*</includes> <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> <sourceDirectories>./</sourceDirectories>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -46,6 +46,16 @@ public @interface CompletionContext {
* @since 4.3 * @since 4.3
*/ */
enum ContextMappingType { enum ContextMappingType {
CATEGORY, GEO CATEGORY("category"), GEO("geo");
private final String mappedName;
ContextMappingType(String mappedName) {
this.mappedName = mappedName;
}
public String getMappedName() {
return mappedName;
}
} }
} }

View File

@ -25,26 +25,36 @@ public enum Dynamic {
/** /**
* New fields are added to the mapping. * New fields are added to the mapping.
*/ */
TRUE, TRUE("true"),
/** /**
* New fields are added to the mapping as * New fields are added to the mapping as
* <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime.html">runtime fields</a>. These * <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime.html">runtime fields</a>. These
* fields are not indexed, and are loaded from {@code _source} at query time. * fields are not indexed, and are loaded from {@code _source} at query time.
*/ */
RUNTIME, RUNTIME("runtime"),
/** /**
* New fields are ignored. These fields will not be indexed or searchable, but will still appear in the * New fields are ignored. These fields will not be indexed or searchable, but will still appear in the
* {@code _source} field of returned hits. These fields will not be added to the mapping, and new fields must be added * {@code _source} field of returned hits. These fields will not be added to the mapping, and new fields must be added
* explicitly. * explicitly.
*/ */
FALSE, FALSE("false"),
/** /**
* If new fields are detected, an exception is thrown and the document is rejected. New fields must be explicitly * If new fields are detected, an exception is thrown and the document is rejected. New fields must be explicitly
* added to the mapping. * added to the mapping.
*/ */
STRICT, STRICT("strict"),
/** /**
* Inherit the dynamic setting from their parent object or from the mapping type. * Inherit the dynamic setting from their parent object or from the mapping type.
*/ */
INHERIT INHERIT("nherit");
private final String mappedName;
Dynamic(String mappedName) {
this.mappedName = mappedName;
}
public String getMappedName() {
return mappedName;
}
} }

View File

@ -25,5 +25,15 @@ package org.springframework.data.elasticsearch.annotations;
*/ */
@Deprecated @Deprecated
public enum DynamicMappingValue { 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;
}
} }

View File

@ -26,40 +26,51 @@ package org.springframework.data.elasticsearch.annotations;
* @author Morgan Lutz * @author Morgan Lutz
*/ */
public enum FieldType { public enum FieldType {
Auto, // Auto("auto"), //
Text, // Text("text"), //
Keyword, // Keyword("keyword"), //
Long, // Long("long"), //
Integer, // Integer("integer"), //
Short, // Short("short"), //
Byte, // Byte("byte"), //
Double, // Double("double"), //
Float, // Float("float"), //
Half_Float, // Half_Float("half_float"), //
Scaled_Float, // Scaled_Float("scaled_float"), //
Date, // Date("date"), //
Date_Nanos, // Date_Nanos("date_nanos"), //
Boolean, // Boolean("boolean"), //
Binary, // Binary("binary"), //
Integer_Range, // Integer_Range("integer_range"), //
Float_Range, // Float_Range("float_range"), //
Long_Range, // Long_Range("long_range"), //
Double_Range, // Double_Range("double_range"), //
Date_Range, // Date_Range("date_range"), //
Ip_Range, // Ip_Range("ip_range"), //
Object, // Object("object"), //
Nested, // Nested("nested"), //
Ip, // Ip("ip"), //
TokenCount, // TokenCount("token_count"), //
Percolator, // Percolator("percolator"), //
Flattened, // Flattened("flattened"), //
Search_As_You_Type, // Search_As_You_Type("search_as_you_type"), //
/** @since 4.1 */ /** @since 4.1 */
Rank_Feature, // Rank_Feature("rank_feature"), //
/** @since 4.1 */ /** @since 4.1 */
Rank_Features, // Rank_Features("rank_features"), //
/** since 4.2 */ /** since 4.2 */
Wildcard, // Wildcard("wildcard"), //
/** @since 4.2 */ /** @since 4.2 */
Dense_Vector // Dense_Vector("dense_vector") //
;
private final String mappedName;
FieldType(String mappedName) {
this.mappedName = mappedName;
}
public String getMappedName() {
return mappedName;
}
} }

View File

@ -64,9 +64,9 @@ public class ElasticsearchExceptionTranslator implements PersistenceExceptionTra
} }
if (elasticsearchException instanceof ElasticsearchStatusException) { if (elasticsearchException instanceof ElasticsearchStatusException) {
ElasticsearchStatusException restStatusException = (ElasticsearchStatusException) elasticsearchException; ElasticsearchStatusException elasticsearchStatusException = (ElasticsearchStatusException) elasticsearchException;
return new RestStatusException(restStatusException.status().getStatus(), restStatusException.getMessage(), return new RestStatusException(elasticsearchStatusException.status().getStatus(),
restStatusException.getCause()); elasticsearchStatusException.getMessage(), elasticsearchStatusException);
} }
return new UncategorizedElasticsearchException(ex.getMessage(), ex); return new UncategorizedElasticsearchException(ex.getMessage(), ex);

View File

@ -24,6 +24,7 @@ import java.util.stream.Collectors;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.document.Document; import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.document.NestedMetaData; import org.springframework.data.elasticsearch.core.document.NestedMetaData;
@ -45,6 +46,7 @@ import org.springframework.util.Assert;
* @author Mark Paluch * @author Mark Paluch
* @author Roman Puchkovskiy * @author Roman Puchkovskiy
* @author Matt Gilene * @author Matt Gilene
* @author Sascha Woo
* @since 4.0 * @since 4.0
*/ */
class SearchHitMapping<T> { class SearchHitMapping<T> {
@ -194,7 +196,7 @@ class SearchHitMapping<T> {
*/ */
private SearchHits<?> mapInnerDocuments(SearchHits<SearchDocument> searchHits, Class<T> type) { private SearchHits<?> mapInnerDocuments(SearchHits<SearchDocument> searchHits, Class<T> type) {
if (searchHits.getTotalHits() == 0) { if (searchHits.isEmpty()) {
return searchHits; return searchHits;
} }
@ -239,7 +241,7 @@ class SearchHitMapping<T> {
searchHits.getSuggest()); searchHits.getSuggest());
} }
} catch (Exception e) { } catch (Exception e) {
LOGGER.warn("Could not map inner_hits", e); throw new UncategorizedElasticsearchException("Unable to convert inner hits.", e);
} }
return searchHits; return searchHits;

View File

@ -76,7 +76,10 @@ public abstract class AbstractRangePropertyValueConverter<T> extends AbstractPro
public Object write(Object value) { public Object write(Object value) {
Assert.notNull(value, "value must not be null."); Assert.notNull(value, "value must not be null.");
Assert.isInstanceOf(Range.class, value, "value must be instance of Range.");
if (!Range.class.isAssignableFrom(value.getClass())) {
return value.toString();
}
try { try {
Range<T> range = (Range<T>) value; Range<T> range = (Range<T>) value;

View File

@ -58,6 +58,10 @@ public class DatePropertyValueConverter extends AbstractPropertyValueConverter {
@Override @Override
public Object write(Object value) { public Object write(Object value) {
if (!Date.class.isAssignableFrom(value.getClass())) {
return value.toString();
}
try { try {
return dateConverters.get(0).format((Date) value); return dateConverters.get(0).format((Date) value);
} catch (Exception e) { } catch (Exception e) {

View File

@ -61,6 +61,10 @@ public class TemporalPropertyValueConverter extends AbstractPropertyValueConvert
@Override @Override
public Object write(Object value) { public Object write(Object value) {
if (!TemporalAccessor.class.isAssignableFrom(value.getClass())) {
return value.toString();
}
try { try {
return dateConverters.get(0).format((TemporalAccessor) value); return dateConverters.get(0).format((TemporalAccessor) value);
} catch (Exception e) { } catch (Exception e) {

View File

@ -230,8 +230,7 @@ public class MappingBuilder {
boolean writeNestedProperties = !isRootObject && (isAnyPropertyAnnotatedWithField(entity) || nestedOrObjectField); boolean writeNestedProperties = !isRootObject && (isAnyPropertyAnnotatedWithField(entity) || nestedOrObjectField);
if (writeNestedProperties) { if (writeNestedProperties) {
String type = nestedOrObjectField ? fieldType.toString().toLowerCase() String type = nestedOrObjectField ? fieldType.getMappedName() : FieldType.Object.getMappedName();
: FieldType.Object.toString().toLowerCase();
ObjectNode nestedObjectNode = objectMapper.createObjectNode(); ObjectNode nestedObjectNode = objectMapper.createObjectNode();
nestedObjectNode.put(FIELD_PARAM_TYPE, type); nestedObjectNode.put(FIELD_PARAM_TYPE, type);
@ -247,9 +246,9 @@ public class MappingBuilder {
} }
if (entity != null && entity.dynamic() != Dynamic.INHERIT) { if (entity != null && entity.dynamic() != Dynamic.INHERIT) {
objectNode.put(TYPE_DYNAMIC, entity.dynamic().name().toLowerCase()); objectNode.put(TYPE_DYNAMIC, entity.dynamic().getMappedName());
} else if (dynamicMapping != null) { } else if (dynamicMapping != null) {
objectNode.put(TYPE_DYNAMIC, dynamicMapping.value().name().toLowerCase()); objectNode.put(TYPE_DYNAMIC, dynamicMapping.value().getMappedName());
} }
ObjectNode propertiesNode = objectNode.putObject(FIELD_PROPERTIES); ObjectNode propertiesNode = objectNode.putObject(FIELD_PROPERTIES);
@ -418,7 +417,7 @@ public class MappingBuilder {
ObjectNode contextNode = contextsNode.addObject(); ObjectNode contextNode = contextsNode.addObject();
contextNode.put(FIELD_CONTEXT_NAME, context.name()); contextNode.put(FIELD_CONTEXT_NAME, context.name());
contextNode.put(FIELD_CONTEXT_TYPE, context.type().name().toLowerCase()); contextNode.put(FIELD_CONTEXT_TYPE, context.type().getMappedName());
if (context.precision().length() > 0) { if (context.precision().length() > 0) {
contextNode.put(FIELD_CONTEXT_PRECISION, context.precision()); contextNode.put(FIELD_CONTEXT_PRECISION, context.precision());
@ -450,7 +449,7 @@ public class MappingBuilder {
} }
propertiesNode.set(property.getFieldName(), objectMapper.createObjectNode() // propertiesNode.set(property.getFieldName(), objectMapper.createObjectNode() //
.put(FIELD_PARAM_TYPE, field.type().name().toLowerCase()) // .put(FIELD_PARAM_TYPE, field.type().getMappedName()) //
.put(MAPPING_ENABLED, false) // .put(MAPPING_ENABLED, false) //
); );
@ -479,9 +478,9 @@ public class MappingBuilder {
if (nestedOrObjectField) { if (nestedOrObjectField) {
if (annotation.dynamic() != Dynamic.INHERIT) { if (annotation.dynamic() != Dynamic.INHERIT) {
fieldNode.put(TYPE_DYNAMIC, annotation.dynamic().name().toLowerCase()); fieldNode.put(TYPE_DYNAMIC, annotation.dynamic().getMappedName());
} else if (dynamicMapping != null) { } else if (dynamicMapping != null) {
fieldNode.put(TYPE_DYNAMIC, dynamicMapping.value().name().toLowerCase()); fieldNode.put(TYPE_DYNAMIC, dynamicMapping.value().getMappedName());
} }
} }
} }
@ -530,9 +529,9 @@ public class MappingBuilder {
if (nestedOrObjectField) { if (nestedOrObjectField) {
if (annotation.mainField().dynamic() != Dynamic.INHERIT) { if (annotation.mainField().dynamic() != Dynamic.INHERIT) {
mainFieldNode.put(TYPE_DYNAMIC, annotation.mainField().dynamic().name().toLowerCase()); mainFieldNode.put(TYPE_DYNAMIC, annotation.mainField().dynamic().getMappedName());
} else if (dynamicMapping != null) { } else if (dynamicMapping != null) {
mainFieldNode.put(TYPE_DYNAMIC, dynamicMapping.value().name().toLowerCase()); mainFieldNode.put(TYPE_DYNAMIC, dynamicMapping.value().getMappedName());
} }
} }

View File

@ -237,7 +237,7 @@ public final class MappingParameters {
} }
if (type != FieldType.Auto) { if (type != FieldType.Auto) {
objectNode.put(FIELD_PARAM_TYPE, type.toString().toLowerCase()); objectNode.put(FIELD_PARAM_TYPE, type.getMappedName());
if (type == FieldType.Date) { if (type == FieldType.Date) {
List<String> formats = new ArrayList<>(); List<String> formats = new ArrayList<>();

View File

@ -24,7 +24,8 @@ package org.springframework.data.elasticsearch.core.mapping;
public interface PropertyValueConverter { public interface PropertyValueConverter {
/** /**
* Converts a property value to an elasticsearch value. * Converts a property value to an elasticsearch value. If the converter cannot convert the value, it must return a
* String representation.
* *
* @param value the value to convert, must not be {@literal null} * @param value the value to convert, must not be {@literal null}
* @return The elasticsearch property value, must not be {@literal null} * @return The elasticsearch property value, must not be {@literal null}

View File

@ -1,4 +1,4 @@
Spring Data Elasticsearch 4.3 GA (2021.1.0) Spring Data Elasticsearch 4.3.1 (2021.1.1)
Copyright (c) [2013-2021] Pivotal Software, Inc. Copyright (c) [2013-2021] Pivotal Software, Inc.
This product is licensed to you under the Apache License, Version 2.0 (the "License"). This product is licensed to you under the Apache License, Version 2.0 (the "License").
@ -30,5 +30,6 @@ conditions of the subcomponent's license, as noted in the LICENSE file.

View File

@ -2783,6 +2783,33 @@ public abstract class ElasticsearchTemplateTests {
assertThat(searchHits.getSearchHit(1).getInnerHits("innerHits").getTotalHits()).isEqualTo(1); assertThat(searchHits.getSearchHit(1).getInnerHits("innerHits").getTotalHits()).isEqualTo(1);
} }
@Test // #1997
@DisplayName("should return document with inner hits size zero")
void shouldReturnDocumentWithInnerHitsSizeZero() {
// given
SampleEntity sampleEntity = SampleEntity.builder().id(nextIdAsString()).message("message 1").rate(1)
.version(System.currentTimeMillis()).build();
List<IndexQuery> indexQueries = getIndexQueries(Arrays.asList(sampleEntity));
operations.bulkIndex(indexQueries, IndexCoordinates.of(indexNameProvider.indexName()));
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery())
.withCollapseBuilder(new CollapseBuilder("rate").setInnerHits(new InnerHitBuilder("innerHits").setSize(0)))
.build();
// when
SearchHits<SampleEntity> searchHits = operations.search(searchQuery, SampleEntity.class,
IndexCoordinates.of(indexNameProvider.indexName()));
// then
assertThat(searchHits).isNotNull();
assertThat(searchHits.getTotalHits()).isEqualTo(1);
assertThat(searchHits.getSearchHits()).hasSize(1);
assertThat(searchHits.getSearchHit(0).getContent().getMessage()).isEqualTo("message 1");
}
private IndexQuery getIndexQuery(SampleEntity sampleEntity) { private IndexQuery getIndexQuery(SampleEntity sampleEntity) {
return new IndexQueryBuilder().withId(sampleEntity.getId()).withObject(sampleEntity) return new IndexQueryBuilder().withId(sampleEntity.getId()).withObject(sampleEntity)
.withVersion(sampleEntity.getVersion()).build(); .withVersion(sampleEntity.getVersion()).build();

View File

@ -0,0 +1,82 @@
/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.convert;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.params.provider.Arguments.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Named;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchPersistentEntity;
import org.springframework.lang.Nullable;
/**
* @author Peter-Josef Meisch
*/
public class PropertyValueConvertersUnitTests {
@ParameterizedTest(name = "{0}") // #2018
@MethodSource("propertyValueConverters")
@DisplayName("should return original object on write if it cannot be converted")
void shouldReturnOriginalObjectOnWriteIfItCannotBeConverted(PropertyValueConverter converter) {
NoConverterForThisClass value = new NoConverterForThisClass();
Object written = converter.write(value);
assertThat(written).isEqualTo(value.toString());
}
static Stream<Arguments> propertyValueConverters() {
SimpleElasticsearchMappingContext context = new SimpleElasticsearchMappingContext();
SimpleElasticsearchPersistentEntity<?> persistentEntity = context
.getRequiredPersistentEntity(NoConverterForThisClass.class);
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getRequiredPersistentProperty("property");
List<PropertyValueConverter> converters = new ArrayList<>();
converters.add(new DatePropertyValueConverter(persistentProperty,
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
converters.add(new DateRangePropertyValueConverter(persistentProperty,
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
converters.add(new NumberRangePropertyValueConverter(persistentProperty));
converters.add(new TemporalPropertyValueConverter(persistentProperty,
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
converters.add(new TemporalRangePropertyValueConverter(persistentProperty,
Collections.singletonList(ElasticsearchDateConverter.of(DateFormat.basic_date))));
return converters.stream().map(propertyValueConverter -> arguments(
Named.of(propertyValueConverter.getClass().getSimpleName(), propertyValueConverter)));
}
static class NoConverterForThisClass {
@SuppressWarnings("unused")
@Nullable Long property;
}
}

View File

@ -38,10 +38,14 @@ import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.assertj.core.data.Percentage; import org.assertj.core.data.Percentage;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.*; import org.springframework.data.elasticsearch.annotations.*;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations; import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
@ -57,6 +61,7 @@ import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm;
import org.springframework.data.elasticsearch.core.suggest.Completion; import org.springframework.data.elasticsearch.core.suggest.Completion;
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration; import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
import org.springframework.data.elasticsearch.utils.IndexNameProvider;
import org.springframework.data.geo.Box; import org.springframework.data.geo.Box;
import org.springframework.data.geo.Circle; import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Point; import org.springframework.data.geo.Point;
@ -79,10 +84,25 @@ import org.springframework.test.context.ContextConfiguration;
* @author Morgan Lutz * @author Morgan Lutz
*/ */
@SpringIntegrationTest @SpringIntegrationTest
@ContextConfiguration(classes = { ElasticsearchRestTemplateConfiguration.class }) @ContextConfiguration(classes = { MappingBuilderIntegrationTests.Config.class })
public class MappingBuilderIntegrationTests extends MappingContextBaseTests { public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Configuration
@Import({ ElasticsearchRestTemplateConfiguration.class })
static class Config {
@Bean
IndexNameProvider indexNameProvider() {
return new IndexNameProvider("mapping-builder");
}
}
@Autowired private ElasticsearchOperations operations; @Autowired private ElasticsearchOperations operations;
@Autowired IndexNameProvider indexNameProvider;
@BeforeEach
public void before() {
indexNameProvider.increment();
}
@Test @Test
@Order(java.lang.Integer.MAX_VALUE) @Order(java.lang.Integer.MAX_VALUE)
@ -132,8 +152,7 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Test // DATAES-76 @Test // DATAES-76
public void shouldAddSampleInheritedEntityDocumentToIndex() { public void shouldAddSampleInheritedEntityDocumentToIndex() {
// given // given
IndexCoordinates index = IndexCoordinates.of("test-index-sample-inherited-mapping-builder"); IndexOperations indexOps = operations.indexOps(SampleInheritedEntity.class);
IndexOperations indexOps = operations.indexOps(index);
// when // when
indexOps.create(); indexOps.create();
@ -142,11 +161,10 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
String message = "msg"; String message = "msg";
String id = "abc"; String id = "abc";
operations.index(new SampleInheritedEntityBuilder(id).createdDate(createdDate).message(message).buildIndex(), operations.index(new SampleInheritedEntityBuilder(id).createdDate(createdDate).message(message).buildIndex(),
index); IndexCoordinates.of(indexNameProvider.indexName()));
operations.indexOps(SampleInheritedEntity.class).refresh();
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).build(); NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).build();
SearchHits<SampleInheritedEntity> result = operations.search(searchQuery, SampleInheritedEntity.class, index); SearchHits<SampleInheritedEntity> result = operations.search(searchQuery, SampleInheritedEntity.class);
// then // then
assertThat(result).hasSize(1); assertThat(result).hasSize(1);
@ -163,7 +181,7 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
IndexOperations indexOpsUser = operations.indexOps(User.class); IndexOperations indexOpsUser = operations.indexOps(User.class);
indexOpsUser.create(); indexOpsUser.create();
indexOpsUser.putMapping(User.class); indexOpsUser.putMapping(User.class);
indexNameProvider.increment();
IndexOperations indexOpsGroup = operations.indexOps(Group.class); IndexOperations indexOpsGroup = operations.indexOps(Group.class);
indexOpsGroup.create(); indexOpsGroup.create();
indexOpsGroup.putMapping(Group.class); indexOpsGroup.putMapping(Group.class);
@ -336,11 +354,19 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
@Test // #2024
@DisplayName("should map all field type values")
void shouldMapAllFieldTypeValues() {
operations.indexOps(EntityWithAllTypes.class).createWithMapping();
}
// region entities // region entities
@Document(indexName = "ignore-above-index") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class IgnoreAboveEntity { static class IgnoreAboveEntity {
@Nullable @Id private String id; @Nullable
@Nullable @Field(type = FieldType.Keyword, ignoreAbove = 10) private String message; @Id private String id;
@Nullable
@Field(type = FieldType.Keyword, ignoreAbove = 10) private String message;
@Nullable @Nullable
public String getId() { public String getId() {
@ -365,57 +391,76 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "fieldname-index") @Document(indexName = "fieldname-index")
static class IdEntity { static class IdEntity {
@Nullable @Id @Field("id-property") private String id; @Nullable
@Id
@Field("id-property") private String id;
} }
@Document(indexName = "fieldname-index") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class TextEntity { 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) // @Field(name = "text-property", type = FieldType.Text) //
@Nullable private String textProperty; @Nullable private String textProperty;
} }
@Document(indexName = "fieldname-index") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class MappingEntity { 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; @Nullable private byte[] mappingProperty;
} }
@Document(indexName = "fieldname-index") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class GeoPointEntity { 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") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class CircularEntity { 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; private CircularEntity circularProperty;
} }
@Document(indexName = "fieldname-index") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class CompletionEntity { 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; private Completion suggest;
} }
@Document(indexName = "fieldname-index") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class MultiFieldEntity { static class MultiFieldEntity {
@Nullable @Id @Field("id-property") private String id; @Nullable
@Id
@Field("id-property") private String id;
@Nullable // @Nullable //
@MultiField(mainField = @Field(name = "main-field", type = FieldType.Text, analyzer = "whitespace"), @MultiField(mainField = @Field(name = "main-field", type = FieldType.Text, analyzer = "whitespace"),
@ -425,13 +470,17 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "test-index-book-mapping-builder") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class Book { static class Book {
@Nullable @Id private String id; @Nullable
@Id private String id;
@Nullable private String name; @Nullable private String name;
@Nullable @Field(type = FieldType.Object) private Author author; @Nullable
@Nullable @Field(type = FieldType.Nested) private Map<Integer, Collection<String>> buckets = new HashMap<>(); @Field(type = FieldType.Object) private Author author;
@Nullable @MultiField(mainField = @Field(type = FieldType.Text, analyzer = "whitespace"), @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", otherFields = { @InnerField(suffix = "prefix", type = FieldType.Text, analyzer = "stop",
searchAnalyzer = "standard") }) private String description; searchAnalyzer = "standard") }) private String description;
@ -481,11 +530,12 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "test-index-simple-recursive-mapping-builder") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class SimpleRecursiveEntity { static class SimpleRecursiveEntity {
@Nullable @Id private String id; @Nullable
@Nullable @Field(type = FieldType.Object, @Id private String id;
ignoreFields = { "circularObject" }) private SimpleRecursiveEntity circularObject; @Nullable
@Field(type = FieldType.Object, ignoreFields = { "circularObject" }) private SimpleRecursiveEntity circularObject;
@Nullable @Nullable
public String getId() { public String getId() {
@ -506,12 +556,16 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "test-copy-to-mapping-builder") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class CopyToEntity { static class CopyToEntity {
@Nullable @Id private String id; @Nullable
@Nullable @Field(type = FieldType.Keyword, copyTo = "name") private String firstName; @Id private String id;
@Nullable @Field(type = FieldType.Keyword, copyTo = "name") private String lastName; @Nullable
@Nullable @Field(type = FieldType.Keyword) private String name; @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 @Nullable
public String getId() { public String getId() {
@ -550,12 +604,15 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "test-index-normalizer-mapping-builder") @Document(indexName = "#{@indexNameProvider.indexName()}")
@Setting(settingPath = "/settings/test-normalizer.json") @Setting(settingPath = "/settings/test-normalizer.json")
static class NormalizerEntity { static class NormalizerEntity {
@Nullable @Id private String id; @Nullable
@Nullable @Field(type = FieldType.Keyword, normalizer = "lower_case_normalizer") private String name; @Id private String id;
@Nullable @MultiField(mainField = @Field(type = FieldType.Text), otherFields = { @InnerField(suffix = "lower_case", @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; type = FieldType.Keyword, normalizer = "lower_case_normalizer") }) private String description;
@Nullable @Nullable
@ -610,10 +667,11 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "test-index-sample-inherited-mapping-builder") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class SampleInheritedEntity extends AbstractInheritedEntity { 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 @Nullable
public String getMessage() { public String getMessage() {
@ -656,11 +714,13 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "test-index-stock-mapping-builder") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class StockPrice { static class StockPrice {
@Nullable @Id private String id; @Nullable
@Id private String id;
@Nullable private String symbol; @Nullable private String symbol;
@Nullable @Field(type = FieldType.Double) private BigDecimal price; @Nullable
@Field(type = FieldType.Double) private BigDecimal price;
@Nullable @Nullable
public String getId() { public String getId() {
@ -691,8 +751,10 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
static class AbstractInheritedEntity { static class AbstractInheritedEntity {
@Nullable @Id private String id; @Nullable
@Nullable @Field(type = FieldType.Date, format = DateFormat.date_time, index = false) private Date createdDate; @Id private String id;
@Nullable
@Field(type = FieldType.Date, format = DateFormat.date_time, index = false) private Date createdDate;
@Nullable @Nullable
public String getId() { public String getId() {
@ -713,21 +775,27 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "test-index-geo-mapping-builder") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class GeoEntity { static class GeoEntity {
@Nullable @Id private String id; @Nullable
@Id private String id;
// geo shape - Spring Data // geo shape - Spring Data
@Nullable private Box box; @Nullable private Box box;
@Nullable private Circle circle; @Nullable private Circle circle;
@Nullable private Polygon polygon; @Nullable private Polygon polygon;
// geo point - Custom implementation + Spring Data // geo point - Custom implementation + Spring Data
@Nullable @GeoPointField private Point pointA; @Nullable
@GeoPointField private Point pointA;
@Nullable private GeoPoint pointB; @Nullable private GeoPoint pointB;
@Nullable @GeoPointField private String pointC; @Nullable
@Nullable @GeoPointField private double[] pointD; @GeoPointField private String pointC;
@Nullable
@GeoPointField private double[] pointD;
// geo shape, until e have the classes for this, us a strng // geo shape, until e have the classes for this, us a strng
@Nullable @GeoShapeField private String shape1; @Nullable
@Nullable @GeoShapeField(coerce = true, ignoreMalformed = true, ignoreZValue = false, @GeoShapeField private String shape1;
@Nullable
@GeoShapeField(coerce = true, ignoreMalformed = true, ignoreZValue = false,
orientation = GeoShapeField.Orientation.clockwise) private String shape2; orientation = GeoShapeField.Orientation.clockwise) private String shape2;
@Nullable @Nullable
@ -821,17 +889,21 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "test-index-user-mapping-builder") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class User { 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<>(); @Field(type = FieldType.Nested, ignoreFields = { "users" }) private Set<Group> groups = new HashSet<>();
} }
@Document(indexName = "test-index-group-mapping-builder") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class Group { static class Group {
@Nullable @Id String id; @Nullable
@Id String id;
@Field(type = FieldType.Nested, ignoreFields = { "groups" }) private Set<User> users = new HashSet<>(); @Field(type = FieldType.Nested, ignoreFields = { "groups" }) private Set<User> users = new HashSet<>();
} }
@ -848,11 +920,14 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "completion") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class CompletionDocument { static class CompletionDocument {
@Nullable @Id private String id; @Nullable
@Nullable @CompletionField(contexts = { @CompletionContext(name = "location", @Id private String id;
type = CompletionContext.ContextMappingType.GEO, path = "proppath") }) private Completion suggest; @Nullable
@CompletionField(contexts = { @CompletionContext(name = "location", type = CompletionContext.ContextMappingType.GEO,
path = "proppath") }) private Completion suggest;
@Nullable @Nullable
public String getId() { public String getId() {
@ -873,9 +948,10 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "test-index-entity-with-seq-no-primary-term-mapping-builder") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class EntityWithSeqNoPrimaryTerm { static class EntityWithSeqNoPrimaryTerm {
@Nullable @Field(type = Object) private SeqNoPrimaryTerm seqNoPrimaryTerm; @Nullable
@Field(type = Object) private SeqNoPrimaryTerm seqNoPrimaryTerm;
@Nullable @Nullable
public SeqNoPrimaryTerm getSeqNoPrimaryTerm() { public SeqNoPrimaryTerm getSeqNoPrimaryTerm() {
@ -888,10 +964,14 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
static class RankFeatureEntity { static class RankFeatureEntity {
@Nullable @Id private String id; @Nullable
@Nullable @Field(type = FieldType.Rank_Feature) private Integer pageRank; @Id private String id;
@Nullable @Field(type = FieldType.Rank_Feature, positiveScoreImpact = false) private Integer urlLength; @Nullable
@Nullable @Field(type = FieldType.Rank_Features) private Map<String, Integer> topics; @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 @Nullable
public String getId() { public String getId() {
@ -930,18 +1010,25 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "termvectors-test") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class TermVectorFieldEntity { static class TermVectorFieldEntity {
@Nullable @Id private String id; @Nullable
@Nullable @Field(type = FieldType.Text, termVector = TermVector.no) private String no; @Id private String id;
@Nullable @Field(type = FieldType.Text, termVector = TermVector.yes) private String yes; @Nullable
@Nullable @Field(type = FieldType.Text, termVector = TermVector.with_positions) private String with_positions; @Field(type = FieldType.Text, termVector = TermVector.no) private String no;
@Nullable @Field(type = FieldType.Text, termVector = TermVector.with_offsets) private String with_offsets; @Nullable
@Nullable @Field(type = FieldType.Text, @Field(type = FieldType.Text, termVector = TermVector.yes) private String yes;
termVector = TermVector.with_positions_offsets) private String with_positions_offsets; @Nullable
@Nullable @Field(type = FieldType.Text, @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; 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; termVector = TermVector.with_positions_offsets_payloads) private String with_positions_offsets_payloads;
@Nullable @Nullable
@ -1017,10 +1104,12 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "wildcard-test") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class WildcardEntity { static class WildcardEntity {
@Nullable @Field(type = Wildcard) private String wildcardWithoutParams; @Nullable
@Nullable @Field(type = Wildcard, nullValue = "WILD", ignoreAbove = 42) private String wildcardWithParams; @Field(type = Wildcard) private String wildcardWithoutParams;
@Nullable
@Field(type = Wildcard, nullValue = "WILD", ignoreAbove = 42) private String wildcardWithParams;
@Nullable @Nullable
public String getWildcardWithoutParams() { public String getWildcardWithoutParams() {
@ -1041,11 +1130,13 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "disabled-entity-mapping") @Document(indexName = "#{@indexNameProvider.indexName()}")
@Mapping(enabled = false) @Mapping(enabled = false)
static class DisabledMappingEntity { static class DisabledMappingEntity {
@Nullable @Id private String id; @Nullable
@Nullable @Field(type = Text) private String text; @Id private String id;
@Nullable
@Field(type = Text) private String text;
@Nullable @Nullable
public String getId() { public String getId() {
@ -1068,9 +1159,13 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
@Document(indexName = "disabled-property-mapping") @Document(indexName = "disabled-property-mapping")
static class DisabledMappingProperty { static class DisabledMappingProperty {
@Nullable @Id private String id; @Nullable
@Nullable @Field(type = Text) private String text; @Id private String id;
@Nullable @Mapping(enabled = false) @Field(type = Object) private Object object; @Nullable
@Field(type = Text) private String text;
@Nullable
@Mapping(enabled = false)
@Field(type = Object) private Object object;
@Nullable @Nullable
public String getId() { public String getId() {
@ -1100,10 +1195,12 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "densevector-test") @Document(indexName = "#{@indexNameProvider.indexName()}")
static class DenseVectorEntity { static class DenseVectorEntity {
@Nullable @Id private String id; @Nullable
@Nullable @Field(type = Dense_Vector, dims = 3) private float[] dense_vector; @Id private String id;
@Nullable
@Field(type = Dense_Vector, dims = 3) private float[] dense_vector;
@Nullable @Nullable
public String getId() { public String getId() {
@ -1124,15 +1221,19 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "dynamic-mapping-annotation") @Document(indexName = "#{@indexNameProvider.indexName()}")
@DynamicMapping(DynamicMappingValue.False) @DynamicMapping(DynamicMappingValue.False)
static class DynamicMappingAnnotationEntity { static class DynamicMappingAnnotationEntity {
@Nullable @DynamicMapping(DynamicMappingValue.Strict) @Field(type = FieldType.Object) private Author author; @Nullable
@Nullable @DynamicMapping(DynamicMappingValue.False) @Field( @DynamicMapping(DynamicMappingValue.Strict)
type = FieldType.Object) private Map<String, Object> objectMap; @Field(type = FieldType.Object) private Author author;
@Nullable @DynamicMapping(DynamicMappingValue.False) @Field( @Nullable
type = FieldType.Nested) private List<Map<String, Object>> nestedObjectMap; @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 @Nullable
public Author getAuthor() { public Author getAuthor() {
@ -1144,57 +1245,140 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
} }
} }
@Document(indexName = "dynamic-mapping", dynamic = Dynamic.FALSE) @Document(indexName = "#{@indexNameProvider.indexName()}")
static class DynamicMappingEntity { static class DynamicMappingEntity {
@Nullable @Field(type = FieldType.Object) // @Nullable
@Field(type = FieldType.Object) //
private Map<String, Object> objectInherit; private Map<String, Object> objectInherit;
@Nullable @Field(type = FieldType.Object, dynamic = Dynamic.FALSE) // @Nullable
@Field(type = FieldType.Object, dynamic = Dynamic.FALSE) //
private Map<String, Object> objectFalse; private Map<String, Object> objectFalse;
@Nullable @Field(type = FieldType.Object, dynamic = Dynamic.TRUE) // @Nullable
@Field(type = FieldType.Object, dynamic = Dynamic.TRUE) //
private Map<String, Object> objectTrue; private Map<String, Object> objectTrue;
@Nullable @Field(type = FieldType.Object, dynamic = Dynamic.STRICT) // @Nullable
@Field(type = FieldType.Object, dynamic = Dynamic.STRICT) //
private Map<String, Object> objectStrict; private Map<String, Object> objectStrict;
@Nullable @Field(type = FieldType.Object, dynamic = Dynamic.RUNTIME) // @Nullable
@Field(type = FieldType.Object, dynamic = Dynamic.RUNTIME) //
private Map<String, Object> objectRuntime; private Map<String, Object> objectRuntime;
@Nullable @Field(type = FieldType.Nested) // @Nullable
@Field(type = FieldType.Nested) //
private List<Map<String, Object>> nestedObjectInherit; private List<Map<String, Object>> nestedObjectInherit;
@Nullable @Field(type = FieldType.Nested, dynamic = Dynamic.FALSE) // @Nullable
@Field(type = FieldType.Nested, dynamic = Dynamic.FALSE) //
private List<Map<String, Object>> nestedObjectFalse; private List<Map<String, Object>> nestedObjectFalse;
@Nullable @Field(type = FieldType.Nested, dynamic = Dynamic.TRUE) // @Nullable
@Field(type = FieldType.Nested, dynamic = Dynamic.TRUE) //
private List<Map<String, Object>> nestedObjectTrue; private List<Map<String, Object>> nestedObjectTrue;
@Nullable @Field(type = FieldType.Nested, dynamic = Dynamic.STRICT) // @Nullable
@Field(type = FieldType.Nested, dynamic = Dynamic.STRICT) //
private List<Map<String, Object>> nestedObjectStrict; private List<Map<String, Object>> nestedObjectStrict;
@Nullable @Field(type = FieldType.Nested, dynamic = Dynamic.RUNTIME) // @Nullable
@Field(type = FieldType.Nested, dynamic = Dynamic.RUNTIME) //
private List<Map<String, Object>> nestedObjectRuntime; private List<Map<String, Object>> nestedObjectRuntime;
} }
@Document(indexName = "dynamic-detection-mapping-true") @Document(indexName = "#{@indexNameProvider.indexName()}")
@Mapping(dateDetection = Mapping.Detection.TRUE, numericDetection = Mapping.Detection.TRUE, @Mapping(dateDetection = Mapping.Detection.TRUE, numericDetection = Mapping.Detection.TRUE,
dynamicDateFormats = { "MM/dd/yyyy" }) dynamicDateFormats = { "MM/dd/yyyy" })
private static class DynamicDetectionMapping { private static class DynamicDetectionMapping {
@Id @Nullable private String id; @Id
@Nullable private String id;
} }
@Document(indexName = "runtime-fields") @Document(indexName = "#{@indexNameProvider.indexName()}")
@Mapping(runtimeFieldsPath = "/mappings/runtime-fields.json") @Mapping(runtimeFieldsPath = "/mappings/runtime-fields.json")
private static class RuntimeFieldEntity { private static class RuntimeFieldEntity {
@Id @Nullable private String id; @Id
@Field(type = Date, format = DateFormat.epoch_millis, name = "@timestamp") @Nullable private Instant timestamp; @Nullable private String id;
@Field(type = Date, format = DateFormat.epoch_millis, name = "@timestamp")
@Nullable private Instant timestamp;
} }
@Document(indexName = "fields-excluded-from-source") @Document(indexName = "#{@indexNameProvider.indexName()}")
private static class ExcludedFieldEntity { private static class ExcludedFieldEntity {
@Id @Nullable private String id; @Id
@Nullable @Field(name = "excluded-date", type = Date, format = DateFormat.date, @Nullable private String id;
@Nullable
@Field(name = "excluded-date", type = Date, format = DateFormat.date,
excludeFromSource = true) private LocalDate excludedDate; excludeFromSource = true) private LocalDate excludedDate;
@Nullable @Field(type = Nested) private NestedExcludedFieldEntity nestedEntity; @Nullable
@Field(type = Nested) private NestedExcludedFieldEntity nestedEntity;
} }
private static class NestedExcludedFieldEntity { private static class NestedExcludedFieldEntity {
@Nullable @Field(name = "excluded-text", type = Text, excludeFromSource = true) private String excludedText; @Nullable
@Field(name = "excluded-text", type = Text, excludeFromSource = true) private String excludedText;
} }
@Document(indexName = "#{@indexNameProvider.indexName()}")
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;
}
// endregion // endregion
} }

View File

@ -265,23 +265,30 @@ public class SimpleElasticsearchPersistentPropertyUnitTests {
// region entities // region entities
static class FieldNameProperty { static class FieldNameProperty {
@Nullable @Field(name = "by-name") String fieldProperty; @Nullable
@Field(name = "by-name") String fieldProperty;
} }
static class FieldValueProperty { static class FieldValueProperty {
@Nullable @Field(value = "by-value") String fieldProperty; @Nullable
@Field(value = "by-value") String fieldProperty;
} }
static class MultiFieldProperty { static class MultiFieldProperty {
@Nullable @MultiField(mainField = @Field("mainfield"), @Nullable
@MultiField(mainField = @Field("mainfield"),
otherFields = { @InnerField(suffix = "suff", type = FieldType.Keyword) }) String mainfieldProperty; otherFields = { @InnerField(suffix = "suff", type = FieldType.Keyword) }) String mainfieldProperty;
} }
static class DatesProperty { static class DatesProperty {
@Nullable @Field(type = FieldType.Date, format = {}, pattern = "dd.MM.uuuu") LocalDate localDate; @Nullable
@Nullable @Field(type = FieldType.Date, format = DateFormat.basic_date_time) LocalDateTime localDateTime; @Field(type = FieldType.Date, format = {}, pattern = "dd.MM.uuuu") LocalDate localDate;
@Nullable @Field(type = FieldType.Date, format = DateFormat.basic_date_time) Date legacyDate; @Nullable
@Nullable @Field(type = FieldType.Date, format = {}, pattern = "dd.MM.uuuu") List<LocalDate> localDateList; @Field(type = FieldType.Date, format = DateFormat.basic_date_time) LocalDateTime localDateTime;
@Nullable
@Field(type = FieldType.Date, format = DateFormat.basic_date_time) Date legacyDate;
@Nullable
@Field(type = FieldType.Date, format = {}, pattern = "dd.MM.uuuu") List<LocalDate> localDateList;
} }
static class SeqNoPrimaryTermProperty { static class SeqNoPrimaryTermProperty {
@ -344,8 +351,10 @@ public class SimpleElasticsearchPersistentPropertyUnitTests {
private static class EntityWithCustomValueConverters { private static class EntityWithCustomValueConverters {
@Id private String id; @Id private String id;
@Nullable @ValueConverter(ClassBasedValueConverter.class) private String fieldWithClassBasedConverter; @Nullable
@Nullable @ValueConverter(EnumBasedValueConverter.class) private String fieldWithEnumBasedConverter; @ValueConverter(ClassBasedValueConverter.class) private String fieldWithClassBasedConverter;
@Nullable
@ValueConverter(EnumBasedValueConverter.class) private String fieldWithEnumBasedConverter;
} }
private static class ClassBasedValueConverter implements PropertyValueConverter { private static class ClassBasedValueConverter implements PropertyValueConverter {