From 79cef262c9940639aa67c156758619a321849a39 Mon Sep 17 00:00:00 2001 From: Peter-Josef Meisch Date: Thu, 14 Jan 2021 23:39:37 +0100 Subject: [PATCH] Use FieldNamingStrategy for property name matching. --- .../elasticsearch-object-mapping.adoc | 7 ++ .../ElasticsearchConfigurationSupport.java | 13 +++ .../SimpleElasticsearchMappingContext.java | 21 +++- ...SimpleElasticsearchPersistentProperty.java | 22 +++- .../core/geo/GeoPointUnitTests.java | 4 +- ...NamingStrategyIntegrationReactiveTest.java | 94 ++++++++++++++++ ...NamingStrategyIntegrationTemplateTest.java | 27 +++++ .../FieldNamingStrategyIntegrationTest.java | 101 ++++++++++++++++++ ...pleElasticsearchPersistentEntityTests.java | 2 +- ...sticsearchPersistentPropertyUnitTests.java | 58 ++++++++++ ...lasticsearchRestTemplateConfiguration.java | 6 +- ...asticsearchRepositoryIntegrationTests.java | 6 ++ 12 files changed, 354 insertions(+), 7 deletions(-) create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/mapping/FieldNamingStrategyIntegrationReactiveTest.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/mapping/FieldNamingStrategyIntegrationTemplateTest.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/mapping/FieldNamingStrategyIntegrationTest.java diff --git a/src/main/asciidoc/reference/elasticsearch-object-mapping.adoc b/src/main/asciidoc/reference/elasticsearch-object-mapping.adoc index 44986e18f..e39f15358 100644 --- a/src/main/asciidoc/reference/elasticsearch-object-mapping.adoc +++ b/src/main/asciidoc/reference/elasticsearch-object-mapping.adoc @@ -71,6 +71,13 @@ This is due to a https://www.elastic.co/guide/en/elasticsearch/reference/current The mapping metadata infrastructure is defined in a separate spring-data-commons project that is technology agnostic. +==== Mapped field names + +Without further configuration, Spring Data Elasticsearch will use the property name of an object as field name in Elasticsearch. This can be changed for individual field by using the `@Field` annotation on that property. + +It is also possible to define a `FieldNamingStrategy` in the configuration of the client (<>). If for example a `SnakeCaseFieldNamingStrategy` is configured, the property _sampleProperty_ of the object would be mapped to _sample_property_ in Elasticsearch. A `FieldNamingStrategy` applies to all entities; it can be overwritten by +setting a specific name with `@Field` on a property. + [[elasticsearch.mapping.meta-model.rules]] === Mapping Rules diff --git a/src/main/java/org/springframework/data/elasticsearch/config/ElasticsearchConfigurationSupport.java b/src/main/java/org/springframework/data/elasticsearch/config/ElasticsearchConfigurationSupport.java index 93367b0dc..5697a5a33 100644 --- a/src/main/java/org/springframework/data/elasticsearch/config/ElasticsearchConfigurationSupport.java +++ b/src/main/java/org/springframework/data/elasticsearch/config/ElasticsearchConfigurationSupport.java @@ -33,6 +33,8 @@ import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions; import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter; import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext; +import org.springframework.data.mapping.model.FieldNamingStrategy; +import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -69,6 +71,7 @@ public SimpleElasticsearchMappingContext elasticsearchMappingContext( SimpleElasticsearchMappingContext mappingContext = new SimpleElasticsearchMappingContext(); mappingContext.setInitialEntitySet(getInitialEntitySet()); mappingContext.setSimpleTypeHolder(elasticsearchCustomConversions.getSimpleTypeHolder()); + mappingContext.setFieldNamingStrategy(fieldNamingStrategy()); return mappingContext; } @@ -160,4 +163,14 @@ protected Set> scanForEntities(String basePackage) { protected RefreshPolicy refreshPolicy() { return null; } + + /** + * Configures a {@link FieldNamingStrategy} on the {@link SimpleElasticsearchMappingContext} instance created. + * + * @return the {@link FieldNamingStrategy} to use + * @since 4.2 + */ + protected FieldNamingStrategy fieldNamingStrategy() { + return PropertyNameFieldNamingStrategy.INSTANCE; + } } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchMappingContext.java b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchMappingContext.java index b0aa32f35..25181b2f4 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchMappingContext.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchMappingContext.java @@ -16,9 +16,12 @@ package org.springframework.data.elasticsearch.core.mapping; import org.springframework.data.mapping.context.AbstractMappingContext; +import org.springframework.data.mapping.model.FieldNamingStrategy; import org.springframework.data.mapping.model.Property; +import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.util.TypeInformation; +import org.springframework.lang.Nullable; /** * SimpleElasticsearchMappingContext @@ -31,6 +34,22 @@ public class SimpleElasticsearchMappingContext extends AbstractMappingContext, ElasticsearchPersistentProperty> { + private static final FieldNamingStrategy DEFAULT_NAMING_STRATEGY = PropertyNameFieldNamingStrategy.INSTANCE; + + private FieldNamingStrategy fieldNamingStrategy = DEFAULT_NAMING_STRATEGY; + + /** + * Configures the {@link FieldNamingStrategy} to be used to determine the field name if no manual mapping is applied. + * Defaults to a strategy using the plain property name. + * + * @param fieldNamingStrategy the {@link FieldNamingStrategy} to be used to determine the field name if no manual + * mapping is applied. + * @since 4.2 + */ + public void setFieldNamingStrategy(@Nullable FieldNamingStrategy fieldNamingStrategy) { + this.fieldNamingStrategy = fieldNamingStrategy == null ? DEFAULT_NAMING_STRATEGY : fieldNamingStrategy; + } + @Override protected SimpleElasticsearchPersistentEntity createPersistentEntity(TypeInformation typeInformation) { return new SimpleElasticsearchPersistentEntity<>(typeInformation); @@ -39,6 +58,6 @@ protected SimpleElasticsearchPersistentEntity createPersistentEntity(Type @Override protected ElasticsearchPersistentProperty createPersistentProperty(Property property, SimpleElasticsearchPersistentEntity owner, SimpleTypeHolder simpleTypeHolder) { - return new SimpleElasticsearchPersistentProperty(property, owner, simpleTypeHolder); + return new SimpleElasticsearchPersistentProperty(property, owner, simpleTypeHolder, fieldNamingStrategy); } } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java index bffb21338..7ee30ff0b 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java @@ -42,7 +42,9 @@ import org.springframework.data.mapping.MappingException; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty; +import org.springframework.data.mapping.model.FieldNamingStrategy; import org.springframework.data.mapping.model.Property; +import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; @@ -72,13 +74,17 @@ public class SimpleElasticsearchPersistentProperty extends private final @Nullable String annotatedFieldName; @Nullable private ElasticsearchPersistentPropertyConverter propertyConverter; private final boolean storeNullValue; + private final FieldNamingStrategy fieldNamingStrategy; public SimpleElasticsearchPersistentProperty(Property property, - PersistentEntity owner, SimpleTypeHolder simpleTypeHolder) { + PersistentEntity owner, SimpleTypeHolder simpleTypeHolder, + @Nullable FieldNamingStrategy fieldNamingStrategy) { super(property, owner, simpleTypeHolder); this.annotatedFieldName = getAnnotatedFieldName(); + this.fieldNamingStrategy = fieldNamingStrategy == null ? PropertyNameFieldNamingStrategy.INSTANCE + : fieldNamingStrategy; this.isId = super.isIdProperty() || SUPPORTED_ID_PROPERTY_NAMES.contains(getFieldName()); // deprecated since 4.1 @@ -233,7 +239,19 @@ private String getAnnotatedFieldName() { @Override public String getFieldName() { - return annotatedFieldName == null ? getProperty().getName() : annotatedFieldName; + + if (annotatedFieldName == null) { + String fieldName = fieldNamingStrategy.getFieldName(this); + + if (!StringUtils.hasText(fieldName)) { + throw new MappingException(String.format("Invalid (null or empty) field name returned for property %s by %s!", + this, fieldNamingStrategy.getClass())); + } + + return fieldName; + } + + return annotatedFieldName; } @Override diff --git a/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoPointUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoPointUnitTests.java index fc504aa79..79aa82c7f 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoPointUnitTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/GeoPointUnitTests.java @@ -7,7 +7,7 @@ import org.springframework.data.geo.Point; /** - * @author P.J. Meisch (pj.meisch@sothawo.com) + * @author Peter-Josef Meisch */ class GeoPointUnitTests { @@ -36,7 +36,7 @@ void shouldConvertToAPoint() { @DisplayName("should not be equal to a Point") void shouldNotBeEqualToAPoint() { - //noinspection AssertBetweenInconvertibleTypes + // noinspection AssertBetweenInconvertibleTypes assertThat(new GeoPoint(48, 8)).isNotEqualTo(new Point(8, 48)); } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/mapping/FieldNamingStrategyIntegrationReactiveTest.java b/src/test/java/org/springframework/data/elasticsearch/core/mapping/FieldNamingStrategyIntegrationReactiveTest.java new file mode 100644 index 000000000..2fc442696 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/mapping/FieldNamingStrategyIntegrationReactiveTest.java @@ -0,0 +1,94 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.mapping; + +import static org.assertj.core.api.Assertions.*; +import static org.elasticsearch.index.query.QueryBuilders.*; + +import lombok.Builder; +import lombok.Data; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.annotation.Id; +import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.annotations.Field; +import org.springframework.data.elasticsearch.annotations.FieldType; +import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations; +import org.springframework.data.elasticsearch.core.ReactiveIndexOperations; +import org.springframework.data.elasticsearch.core.SearchHits; +import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; +import org.springframework.data.elasticsearch.core.query.Query; +import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchRestTemplateConfiguration; +import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; +import org.springframework.data.mapping.model.FieldNamingStrategy; +import org.springframework.data.mapping.model.SnakeCaseFieldNamingStrategy; +import org.springframework.test.context.ContextConfiguration; +import reactor.test.StepVerifier; + +/** + * @author Peter-Josef Meisch + */ +@SpringIntegrationTest +@ContextConfiguration(classes = { FieldNamingStrategyIntegrationReactiveTest.Config.class }) +public class FieldNamingStrategyIntegrationReactiveTest { + + @Autowired private ReactiveElasticsearchOperations operations; + + @Configuration + static class Config extends ReactiveElasticsearchRestTemplateConfiguration { + + @Override + protected FieldNamingStrategy fieldNamingStrategy() { + return new SnakeCaseFieldNamingStrategy(); + } + } + + @BeforeEach + void setUp() { + ReactiveIndexOperations indexOps = this.operations.indexOps(Entity.class); + indexOps.delete() // + .then(indexOps.create()) // + .then(indexOps.putMapping()) // + .block(); + } + + @Test // #1565 + @DisplayName("should use configured FieldNameStrategy") + void shouldUseConfiguredFieldNameStrategy() { + + Entity entity = new Entity.EntityBuilder().id("42").someText("the text to be searched").build(); + operations.save(entity).block(); + + // use a native query here to prevent automatic property name matching + Query query = new NativeSearchQueryBuilder().withQuery(matchQuery("some_text", "searched")).build(); + operations.search(query, Entity.class) // + .as(StepVerifier::create) // + .expectNextCount(1) // + .verifyComplete(); + } + + @Data + @Builder + @Document(indexName = "field-naming-strategy-test") + static class Entity { + @Id private String id; + @Field(type = FieldType.Text) private String someText; + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/mapping/FieldNamingStrategyIntegrationTemplateTest.java b/src/test/java/org/springframework/data/elasticsearch/core/mapping/FieldNamingStrategyIntegrationTemplateTest.java new file mode 100644 index 000000000..8ae38d4b3 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/mapping/FieldNamingStrategyIntegrationTemplateTest.java @@ -0,0 +1,27 @@ +/* + * (c) Copyright 2021 sothawo + */ +package org.springframework.data.elasticsearch.core.mapping; + +import org.springframework.context.annotation.Configuration; +import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration; +import org.springframework.data.mapping.model.FieldNamingStrategy; +import org.springframework.data.mapping.model.SnakeCaseFieldNamingStrategy; +import org.springframework.test.context.ContextConfiguration; + +/** + * @author P.J. Meisch (pj.meisch@sothawo.com) + */ +@ContextConfiguration(classes = { FieldNamingStrategyIntegrationTemplateTest.Config.class }) +public class FieldNamingStrategyIntegrationTemplateTest extends FieldNamingStrategyIntegrationTest { + + @Configuration + static class Config extends ElasticsearchTemplateConfiguration { + + @Override + protected FieldNamingStrategy fieldNamingStrategy() { + return new SnakeCaseFieldNamingStrategy(); + } + } + +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/mapping/FieldNamingStrategyIntegrationTest.java b/src/test/java/org/springframework/data/elasticsearch/core/mapping/FieldNamingStrategyIntegrationTest.java new file mode 100644 index 000000000..cbb589a78 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/mapping/FieldNamingStrategyIntegrationTest.java @@ -0,0 +1,101 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.elasticsearch.core.mapping; + +import static org.assertj.core.api.Assertions.*; +import static org.elasticsearch.index.query.QueryBuilders.*; + +import lombok.Builder; +import lombok.Data; + +import org.elasticsearch.client.RestHighLevelClient; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.annotation.Id; +import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.annotations.Field; +import org.springframework.data.elasticsearch.annotations.FieldType; +import org.springframework.data.elasticsearch.core.ElasticsearchOperations; +import org.springframework.data.elasticsearch.core.IndexOperations; +import org.springframework.data.elasticsearch.core.SearchHits; +import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; +import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; +import org.springframework.data.elasticsearch.core.query.Query; +import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration; +import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; +import org.springframework.data.mapping.model.FieldNamingStrategy; +import org.springframework.data.mapping.model.SnakeCaseFieldNamingStrategy; +import org.springframework.test.context.ContextConfiguration; + +/** + * @author Peter-Josef Meisch + */ +@SpringIntegrationTest +@ContextConfiguration(classes = { FieldNamingStrategyIntegrationTest.Config.class }) +public class FieldNamingStrategyIntegrationTest { + + @Autowired private ElasticsearchOperations operations; + + @Configuration + static class Config extends ElasticsearchRestTemplateConfiguration { + + @Override + @Bean + public ElasticsearchOperations elasticsearchOperations(ElasticsearchConverter elasticsearchConverter, + RestHighLevelClient elasticsearchClient) { + return super.elasticsearchOperations(elasticsearchConverter, elasticsearchClient); + } + + @Override + protected FieldNamingStrategy fieldNamingStrategy() { + return new SnakeCaseFieldNamingStrategy(); + } + } + + @BeforeEach + void setUp() { + IndexOperations indexOps = this.operations.indexOps(Entity.class); + indexOps.delete(); + indexOps.create(); + indexOps.putMapping(); + } + + @Test // #1565 + @DisplayName("should use configured FieldNameStrategy") + void shouldUseConfiguredFieldNameStrategy() { + + Entity entity = new Entity.EntityBuilder().id("42").someText("the text to be searched").build(); + operations.save(entity); + + // use a native query here to prevent automatic property name matching + Query query = new NativeSearchQueryBuilder().withQuery(matchQuery("some_text", "searched")).build(); + SearchHits searchHits = operations.search(query, Entity.class); + + assertThat(searchHits.getTotalHits()).isEqualTo(1); + } + + @Data + @Builder + @Document(indexName = "field-naming-strategy-test") + static class Entity { + @Id private String id; + @Field(type = FieldType.Text) private String someText; + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntityTests.java b/src/test/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntityTests.java index 215460a4f..90ed02743 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntityTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntityTests.java @@ -152,7 +152,7 @@ private static SimpleElasticsearchPersistentProperty createProperty(SimpleElasti TypeInformation type = entity.getTypeInformation(); Property property = Property.of(type, ReflectionUtils.findField(entity.getType(), field)); - return new SimpleElasticsearchPersistentProperty(property, entity, SimpleTypeHolder.DEFAULT); + return new SimpleElasticsearchPersistentProperty(property, entity, SimpleTypeHolder.DEFAULT, null); } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentPropertyUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentPropertyUnitTests.java index caaad811a..b3e4a1060 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentPropertyUnitTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentPropertyUnitTests.java @@ -37,7 +37,13 @@ import org.springframework.data.elasticsearch.annotations.Score; import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm; import org.springframework.data.mapping.MappingException; +import org.springframework.data.mapping.model.FieldNamingStrategy; +import org.springframework.data.mapping.model.Property; +import org.springframework.data.mapping.model.SimpleTypeHolder; +import org.springframework.data.mapping.model.SnakeCaseFieldNamingStrategy; +import org.springframework.data.util.ClassTypeInformation; import org.springframework.lang.Nullable; +import org.springframework.util.ReflectionUtils; /** * Unit tests for {@link SimpleElasticsearchPersistentProperty}. @@ -200,6 +206,52 @@ void shouldRequirePatternForCustomDateFormat() { .withMessageContaining("pattern"); } + @Test // #1565 + @DisplayName("should use default FieldNamingStrategy") + void shouldUseDefaultFieldNamingStrategy() { + + ElasticsearchPersistentEntity entity = new SimpleElasticsearchPersistentEntity<>( + ClassTypeInformation.from(FieldNamingStrategyEntity.class)); + ClassTypeInformation type = ClassTypeInformation.from(FieldNamingStrategyEntity.class); + + java.lang.reflect.Field field = ReflectionUtils.findField(FieldNamingStrategyEntity.class, + "withoutCustomFieldName"); + SimpleElasticsearchPersistentProperty property = new SimpleElasticsearchPersistentProperty(Property.of(type, field), + entity, SimpleTypeHolder.DEFAULT, null); + + assertThat(property.getFieldName()).isEqualTo("withoutCustomFieldName"); + + field = ReflectionUtils.findField(FieldNamingStrategyEntity.class, "withCustomFieldName"); + property = new SimpleElasticsearchPersistentProperty(Property.of(type, field), entity, SimpleTypeHolder.DEFAULT, + null); + + assertThat(property.getFieldName()).isEqualTo("CUStomFIEldnAME"); + } + + @Test // #1565 + @DisplayName("should use custom FieldNamingStrategy") + void shouldUseCustomFieldNamingStrategy() { + + FieldNamingStrategy fieldNamingStrategy = new SnakeCaseFieldNamingStrategy(); + + ElasticsearchPersistentEntity entity = new SimpleElasticsearchPersistentEntity<>( + ClassTypeInformation.from(FieldNamingStrategyEntity.class)); + ClassTypeInformation type = ClassTypeInformation.from(FieldNamingStrategyEntity.class); + + java.lang.reflect.Field field = ReflectionUtils.findField(FieldNamingStrategyEntity.class, + "withoutCustomFieldName"); + SimpleElasticsearchPersistentProperty property = new SimpleElasticsearchPersistentProperty(Property.of(type, field), + entity, SimpleTypeHolder.DEFAULT, fieldNamingStrategy); + + assertThat(property.getFieldName()).isEqualTo("without_custom_field_name"); + + field = ReflectionUtils.findField(FieldNamingStrategyEntity.class, "withCustomFieldName"); + property = new SimpleElasticsearchPersistentProperty(Property.of(type, field), entity, SimpleTypeHolder.DEFAULT, + fieldNamingStrategy); + + assertThat(property.getFieldName()).isEqualTo("CUStomFIEldnAME"); + } + static class InvalidScoreProperty { @Nullable @Score String scoreProperty; } @@ -245,4 +297,10 @@ static class DateFieldWithCustomFormatAndNoPattern { static class DateNanosFieldWithNoFormat { @Field(type = FieldType.Date_Nanos) LocalDateTime datetime; } + + @Data + static class FieldNamingStrategyEntity { + private String withoutCustomFieldName; + @Field(name = "CUStomFIEldnAME") private String withCustomFieldName; + } } diff --git a/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ElasticsearchRestTemplateConfiguration.java b/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ElasticsearchRestTemplateConfiguration.java index c7a64adb4..0263f6c76 100644 --- a/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ElasticsearchRestTemplateConfiguration.java +++ b/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ElasticsearchRestTemplateConfiguration.java @@ -71,7 +71,8 @@ public RestHighLevelClient elasticsearchClient() { @Override public ElasticsearchOperations elasticsearchOperations(ElasticsearchConverter elasticsearchConverter, RestHighLevelClient elasticsearchClient) { - return new ElasticsearchRestTemplate(elasticsearchClient, elasticsearchConverter) { + + ElasticsearchRestTemplate template = new ElasticsearchRestTemplate(elasticsearchClient, elasticsearchConverter) { @Override public T execute(ClientCallback callback) { try { @@ -84,6 +85,9 @@ public T execute(ClientCallback callback) { } } }; + template.setRefreshPolicy(refreshPolicy()); + + return template; } @Override diff --git a/src/test/java/org/springframework/data/elasticsearch/repository/support/simple/SimpleElasticsearchRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/repository/support/simple/SimpleElasticsearchRepositoryIntegrationTests.java index ec7a77290..fc4f76ece 100644 --- a/src/test/java/org/springframework/data/elasticsearch/repository/support/simple/SimpleElasticsearchRepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/repository/support/simple/SimpleElasticsearchRepositoryIntegrationTests.java @@ -50,8 +50,10 @@ import org.springframework.data.domain.Sort.Order; import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Field; +import org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate; import org.springframework.data.elasticsearch.core.ElasticsearchOperations; import org.springframework.data.elasticsearch.core.IndexOperations; +import org.springframework.data.elasticsearch.core.RefreshPolicy; import org.springframework.data.elasticsearch.core.SearchPage; import org.springframework.data.elasticsearch.core.query.Criteria; import org.springframework.data.elasticsearch.core.query.CriteriaQuery; @@ -642,7 +644,11 @@ void shouldIndexWithoutRefreshEntity() { sampleEntity.setMessage("some message"); // when + AbstractElasticsearchTemplate abstractElasticsearchTemplate = (AbstractElasticsearchTemplate) this.operations; + RefreshPolicy refreshPolicy = abstractElasticsearchTemplate.getRefreshPolicy(); + abstractElasticsearchTemplate.setRefreshPolicy(RefreshPolicy.NONE); repository.indexWithoutRefresh(sampleEntity); + abstractElasticsearchTemplate.setRefreshPolicy(refreshPolicy); // then Page entities = repository.search(termQuery("id", documentId), PageRequest.of(0, 50));