mirror of
				https://github.com/spring-projects/spring-data-elasticsearch.git
				synced 2025-10-31 14:48:56 +00:00 
			
		
		
		
	Add SpEL support for settingPath in @Settings annotation.
Original Pull Request #3188 Closes #3187 Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
This commit is contained in:
		
							parent
							
								
									b552128198
								
							
						
					
					
						commit
						21bc62b78c
					
				| @ -4,10 +4,11 @@ | ||||
| [[new-features.6-0-0]] | ||||
| == New in Spring Data Elasticsearch 6.0 | ||||
| 
 | ||||
| * Upgarde to Spring 7 | ||||
| * Upgrade to Spring 7 | ||||
| * Switch to jspecify nullability annotations | ||||
| * Upgrade to Elasticsearch 9.1.5 | ||||
| * Use the new Elasticsearch Rest5Client as default | ||||
| * Add support for SpEL expressions in the `settingPath` parameter of the `@Setting` annotation | ||||
| 
 | ||||
| 
 | ||||
| [[new-features.5-5-0]] | ||||
|  | ||||
| @ -47,6 +47,7 @@ import org.springframework.data.util.TypeInformation; | ||||
| import org.springframework.expression.EvaluationContext; | ||||
| import org.springframework.expression.EvaluationException; | ||||
| import org.springframework.expression.Expression; | ||||
| import org.springframework.expression.ExpressionException; | ||||
| import org.springframework.expression.ParserContext; | ||||
| import org.springframework.expression.common.LiteralExpression; | ||||
| import org.springframework.expression.spel.standard.SpelExpressionParser; | ||||
| @ -298,7 +299,7 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit | ||||
| 		Assert.notNull(fieldName, "fieldName must not be null"); | ||||
| 
 | ||||
| 		return fieldNamePropertyCache.computeIfAbsent(fieldName, key -> { | ||||
| 			AtomicReference<ElasticsearchPersistentProperty> propertyRef = new AtomicReference<>(); | ||||
| 			AtomicReference<@Nullable ElasticsearchPersistentProperty> propertyRef = new AtomicReference<>(); | ||||
| 			doWithProperties((PropertyHandler<@NonNull ElasticsearchPersistentProperty>) property -> { | ||||
| 				if (key.equals(property.getFieldName())) { | ||||
| 					propertyRef.set(property); | ||||
| @ -423,9 +424,9 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit | ||||
| 
 | ||||
| 		try { | ||||
| 			Expression expression = routingExpressions.computeIfAbsent(routing, PARSER::parseExpression); | ||||
| 			ExpressionDependencies expressionDependencies = ExpressionDependencies.discover(expression); | ||||
| 			ExpressionDependencies expressionDependencies = expression != null ? ExpressionDependencies.discover(expression) | ||||
| 					: ExpressionDependencies.none(); | ||||
| 
 | ||||
| 			// noinspection ConstantConditions | ||||
| 			EvaluationContext context = getEvaluationContext(null, expressionDependencies); | ||||
| 			context.setVariable("entity", bean); | ||||
| 
 | ||||
| @ -440,8 +441,20 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit | ||||
| 
 | ||||
| 	// region index settings | ||||
| 	@Override | ||||
| 	public String settingPath() { | ||||
| 		return settingsParameter.get().settingPath; | ||||
| 	public @Nullable String settingPath() { | ||||
| 		String settingPathFromParameter = settingsParameter.get().settingPath; | ||||
| 		if (settingPathFromParameter == null) { | ||||
| 			return null; | ||||
| 		} | ||||
| 
 | ||||
| 		try { | ||||
| 			Expression expression = PARSER.parseExpression(settingPathFromParameter, ParserContext.TEMPLATE_EXPRESSION); | ||||
| 			return (expression instanceof LiteralExpression) ? settingPathFromParameter | ||||
| 					: expression.getValue(getEvaluationContext(null, ExpressionDependencies.discover(expression)), String.class); | ||||
| 		} catch (ExpressionException e) { | ||||
| 			throw new InvalidDataAccessApiUsageException( | ||||
| 					"Could not resolve expression: " + settingPathFromParameter + " for @Setting.settingPath ", e); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
|  | ||||
| @ -84,7 +84,7 @@ public class QueryStringSpELEvaluator { | ||||
| 
 | ||||
| 		if (expr != null) { | ||||
| 			EvaluationContext context = evaluationContextProvider.getEvaluationContext(parameterAccessor.getValues()) | ||||
| 					.getRequiredEvaluationContext(); | ||||
| 					.getEvaluationContext(); | ||||
| 
 | ||||
| 			if (context instanceof StandardEvaluationContext standardEvaluationContext) { | ||||
| 				standardEvaluationContext.setTypeConverter(elasticsearchSpELTypeConverter); | ||||
|  | ||||
| @ -0,0 +1,17 @@ | ||||
| package org.springframework.data.elasticsearch.core; | ||||
| 
 | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.context.annotation.Configuration; | ||||
| import org.springframework.context.annotation.Import; | ||||
| import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration; | ||||
| 
 | ||||
| public class IndexSettingsELCIntegrationTests extends IndexSettingsIntegrationTests { | ||||
| 	@Configuration | ||||
| 	@Import({ ElasticsearchTemplateConfiguration.class }) | ||||
| 	static class Config { | ||||
| 		@Bean | ||||
| 		public SpelSettingPath spelSettingPath() { | ||||
| 			return new SpelSettingPath(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -0,0 +1,47 @@ | ||||
| package org.springframework.data.elasticsearch.core; | ||||
| 
 | ||||
| import static org.assertj.core.api.Assertions.*; | ||||
| 
 | ||||
| import org.jspecify.annotations.Nullable; | ||||
| import org.junit.jupiter.api.DisplayName; | ||||
| import org.junit.jupiter.api.Test; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.data.annotation.Id; | ||||
| import org.springframework.data.elasticsearch.annotations.Document; | ||||
| import org.springframework.data.elasticsearch.annotations.Setting; | ||||
| import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; | ||||
| 
 | ||||
| /** | ||||
|  * IndexSettings test that need an regular conext setup for SpEL resolution for example. | ||||
|  */ | ||||
| @SpringIntegrationTest | ||||
| public abstract class IndexSettingsIntegrationTests { | ||||
| 
 | ||||
| 	@Autowired protected ElasticsearchOperations operations; | ||||
| 
 | ||||
| 	@Test // #3187 | ||||
| 	@DisplayName("should evaluate SpEL expression in settingPath") | ||||
| 	void shouldEvaluateSpElExpressionInSettingPath() { | ||||
| 
 | ||||
| 		var settingPath = operations.getElasticsearchConverter().getMappingContext() | ||||
| 				.getRequiredPersistentEntity(SettingPathWithSpel.class).settingPath(); | ||||
| 
 | ||||
| 		assertThat(settingPath).isEqualTo(SpelSettingPath.SETTING_PATH); | ||||
| 	} | ||||
| 
 | ||||
| 	protected static class SpelSettingPath { | ||||
| 		public static String SETTING_PATH = "test-setting-path"; | ||||
| 
 | ||||
| 		public String settingPath() { | ||||
| 			return SETTING_PATH; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	@Document(indexName = "foo") | ||||
| 	@Setting(settingPath = "#{@spelSettingPath.settingPath}") | ||||
| 	private static class SettingPathWithSpel { | ||||
| 		@Nullable | ||||
| 		@Id String id; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -19,10 +19,16 @@ import static org.assertj.core.api.Assertions.*; | ||||
| import static org.skyscreamer.jsonassert.JSONAssert.*; | ||||
| 
 | ||||
| import org.json.JSONException; | ||||
| import org.jspecify.annotations.NonNull; | ||||
| import org.jspecify.annotations.Nullable; | ||||
| import org.junit.jupiter.api.BeforeEach; | ||||
| import org.junit.jupiter.api.DisplayName; | ||||
| import org.junit.jupiter.api.Nested; | ||||
| import org.junit.jupiter.api.Test; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.context.ApplicationContext; | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.context.annotation.Configuration; | ||||
| import org.springframework.data.annotation.Id; | ||||
| import org.springframework.data.annotation.Version; | ||||
| import org.springframework.data.elasticsearch.annotations.Document; | ||||
| @ -38,6 +44,7 @@ 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.test.context.junit.jupiter.SpringJUnitConfig; | ||||
| import org.springframework.util.ReflectionUtils; | ||||
| 
 | ||||
| /** | ||||
| @ -60,9 +67,9 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase | ||||
| 		@Test | ||||
| 		public void shouldThrowExceptionGivenVersionPropertyIsNotLong() { | ||||
| 
 | ||||
| 			TypeInformation<EntityWithWrongVersionType> typeInformation = TypeInformation | ||||
| 			TypeInformation<@NonNull EntityWithWrongVersionType> typeInformation = TypeInformation | ||||
| 					.of(EntityWithWrongVersionType.class); | ||||
| 			SimpleElasticsearchPersistentEntity<EntityWithWrongVersionType> entity = new SimpleElasticsearchPersistentEntity<>( | ||||
| 			SimpleElasticsearchPersistentEntity<@NonNull EntityWithWrongVersionType> entity = new SimpleElasticsearchPersistentEntity<>( | ||||
| 					typeInformation, contextConfiguration); | ||||
| 
 | ||||
| 			assertThatThrownBy(() -> createProperty(entity, "version")).isInstanceOf(MappingException.class); | ||||
| @ -71,9 +78,9 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase | ||||
| 		@Test | ||||
| 		public void shouldThrowExceptionGivenMultipleVersionPropertiesArePresent() { | ||||
| 
 | ||||
| 			TypeInformation<EntityWithMultipleVersionField> typeInformation = TypeInformation | ||||
| 			TypeInformation<@NonNull EntityWithMultipleVersionField> typeInformation = TypeInformation | ||||
| 					.of(EntityWithMultipleVersionField.class); | ||||
| 			SimpleElasticsearchPersistentEntity<EntityWithMultipleVersionField> entity = new SimpleElasticsearchPersistentEntity<>( | ||||
| 			SimpleElasticsearchPersistentEntity<@NonNull EntityWithMultipleVersionField> entity = new SimpleElasticsearchPersistentEntity<>( | ||||
| 					typeInformation, contextConfiguration); | ||||
| 			SimpleElasticsearchPersistentProperty persistentProperty1 = createProperty(entity, "version1"); | ||||
| 			SimpleElasticsearchPersistentProperty persistentProperty2 = createProperty(entity, "version2"); | ||||
| @ -100,9 +107,9 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase | ||||
| 		@Test | ||||
| 		// DATAES-799 | ||||
| 		void shouldReportThatThereIsNoSeqNoPrimaryTermPropertyWhenThereIsNoSuchProperty() { | ||||
| 			TypeInformation<EntityWithoutSeqNoPrimaryTerm> typeInformation = TypeInformation | ||||
| 			TypeInformation<@NonNull EntityWithoutSeqNoPrimaryTerm> typeInformation = TypeInformation | ||||
| 					.of(EntityWithoutSeqNoPrimaryTerm.class); | ||||
| 			SimpleElasticsearchPersistentEntity<EntityWithoutSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>( | ||||
| 			SimpleElasticsearchPersistentEntity<@NonNull EntityWithoutSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>( | ||||
| 					typeInformation, contextConfiguration); | ||||
| 
 | ||||
| 			assertThat(entity.hasSeqNoPrimaryTermProperty()).isFalse(); | ||||
| @ -111,9 +118,9 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase | ||||
| 		@Test | ||||
| 		// DATAES-799 | ||||
| 		void shouldReportThatThereIsSeqNoPrimaryTermPropertyWhenThereIsSuchProperty() { | ||||
| 			TypeInformation<EntityWithSeqNoPrimaryTerm> typeInformation = TypeInformation | ||||
| 			TypeInformation<@NonNull EntityWithSeqNoPrimaryTerm> typeInformation = TypeInformation | ||||
| 					.of(EntityWithSeqNoPrimaryTerm.class); | ||||
| 			SimpleElasticsearchPersistentEntity<EntityWithSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>( | ||||
| 			SimpleElasticsearchPersistentEntity<@NonNull EntityWithSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>( | ||||
| 					typeInformation, contextConfiguration); | ||||
| 
 | ||||
| 			entity.addPersistentProperty(createProperty(entity, "seqNoPrimaryTerm")); | ||||
| @ -125,9 +132,9 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase | ||||
| 		// DATAES-799 | ||||
| 		void shouldReturnSeqNoPrimaryTermPropertyWhenThereIsSuchProperty() { | ||||
| 
 | ||||
| 			TypeInformation<EntityWithSeqNoPrimaryTerm> typeInformation = TypeInformation | ||||
| 			TypeInformation<@NonNull EntityWithSeqNoPrimaryTerm> typeInformation = TypeInformation | ||||
| 					.of(EntityWithSeqNoPrimaryTerm.class); | ||||
| 			SimpleElasticsearchPersistentEntity<EntityWithSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>( | ||||
| 			SimpleElasticsearchPersistentEntity<@NonNull EntityWithSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>( | ||||
| 					typeInformation, contextConfiguration); | ||||
| 			entity.addPersistentProperty(createProperty(entity, "seqNoPrimaryTerm")); | ||||
| 			EntityWithSeqNoPrimaryTerm instance = new EntityWithSeqNoPrimaryTerm(); | ||||
| @ -144,9 +151,9 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase | ||||
| 		@Test | ||||
| 		// DATAES-799 | ||||
| 		void shouldNotAllowMoreThanOneSeqNoPrimaryTermProperties() { | ||||
| 			TypeInformation<EntityWithSeqNoPrimaryTerm> typeInformation = TypeInformation | ||||
| 			TypeInformation<@NonNull EntityWithSeqNoPrimaryTerm> typeInformation = TypeInformation | ||||
| 					.of(EntityWithSeqNoPrimaryTerm.class); | ||||
| 			SimpleElasticsearchPersistentEntity<EntityWithSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>( | ||||
| 			SimpleElasticsearchPersistentEntity<@NonNull EntityWithSeqNoPrimaryTerm> entity = new SimpleElasticsearchPersistentEntity<>( | ||||
| 					typeInformation, contextConfiguration); | ||||
| 			entity.addPersistentProperty(createProperty(entity, "seqNoPrimaryTerm")); | ||||
| 
 | ||||
| @ -164,7 +171,24 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase | ||||
| 
 | ||||
| 	@Nested | ||||
| 	@DisplayName("index settings") | ||||
| 	@SpringJUnitConfig({ SettingsTests.Config.class }) | ||||
| 	class SettingsTests { | ||||
| 		@Autowired private ApplicationContext applicationContext; | ||||
| 
 | ||||
| 		@Configuration | ||||
| 		static class Config { | ||||
| 			@Bean | ||||
| 			public SpelTestBean spelTestBean() { | ||||
| 				return new SpelTestBean(); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		@BeforeEach | ||||
| 		void setUp() { | ||||
| 			((SimpleElasticsearchMappingContext) elasticsearchConverter | ||||
| 					.get().getMappingContext()).setApplicationContext(applicationContext); | ||||
| 
 | ||||
| 		} | ||||
| 
 | ||||
| 		@Test // #1719 | ||||
| 		@DisplayName("should error if index sorting parameters do not have the same number of arguments") | ||||
| @ -205,6 +229,24 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase | ||||
| 			String json = entity.getDefaultSettings().toJson(); | ||||
| 			assertEquals(expected, json, false); | ||||
| 		} | ||||
| 
 | ||||
| 		@Test // #3187 | ||||
| 		@DisplayName("should evaluate SpEL expression in settingPath") | ||||
| 		void shouldEvaluateSpElExpressionInSettingPath() { | ||||
| 
 | ||||
| 			var settingPath = elasticsearchConverter.get().getMappingContext() | ||||
| 					.getRequiredPersistentEntity(SettingPathWithSpel.class).settingPath(); | ||||
| 
 | ||||
| 			assertThat(settingPath).isEqualTo(SpelTestBean.SETTING_PATH); | ||||
| 		} | ||||
| 
 | ||||
| 		private static class SpelTestBean { | ||||
| 			public static String SETTING_PATH = "test-setting-path"; | ||||
| 
 | ||||
| 			public String settingPath() { | ||||
| 				return SETTING_PATH; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	@Nested | ||||
| @ -271,7 +313,7 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// region helper functions | ||||
| 	// region helper | ||||
| 	private static SimpleElasticsearchPersistentProperty createProperty(SimpleElasticsearchPersistentEntity<?> entity, | ||||
| 			String fieldName) { | ||||
| 
 | ||||
| @ -282,6 +324,7 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase | ||||
| 		return new SimpleElasticsearchPersistentProperty(property, entity, SimpleTypeHolder.DEFAULT); | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	// endregion | ||||
| 
 | ||||
| 	// region entities | ||||
| @ -295,7 +338,7 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase | ||||
| 			return version; | ||||
| 		} | ||||
| 
 | ||||
| 		public void setVersion(String version) { | ||||
| 		public void setVersion(@Nullable String version) { | ||||
| 			this.version = version; | ||||
| 		} | ||||
| 	} | ||||
| @ -313,7 +356,7 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase | ||||
| 			return version1; | ||||
| 		} | ||||
| 
 | ||||
| 		public void setVersion1(Long version1) { | ||||
| 		public void setVersion1(@Nullable Long version1) { | ||||
| 			this.version1 = version1; | ||||
| 		} | ||||
| 
 | ||||
| @ -322,7 +365,7 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase | ||||
| 			return version2; | ||||
| 		} | ||||
| 
 | ||||
| 		public void setVersion2(Long version2) { | ||||
| 		public void setVersion2(@Nullable Long version2) { | ||||
| 			this.version2 = version2; | ||||
| 		} | ||||
| 	} | ||||
| @ -397,5 +440,12 @@ public class SimpleElasticsearchPersistentEntityTests extends MappingContextBase | ||||
| 		@Nullable | ||||
| 		@Id String id; | ||||
| 	} | ||||
| 
 | ||||
| 	@Document(indexName = "foo") | ||||
| 	@Setting(settingPath = "#{@spelTestBean.settingPath}") | ||||
| 	private static class SettingPathWithSpel { | ||||
| 		@Nullable | ||||
| 		@Id String id; | ||||
| 	} | ||||
| 	// endregion | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user