Add support for Value Expressions in @KeySpace.

Closes #613
This commit is contained in:
Mark Paluch
2024-12-16 14:38:18 +01:00
parent e2c7be2c7a
commit a1fd61e22c
6 changed files with 20 additions and 12 deletions

View File

@@ -7,6 +7,7 @@
** xref:repositories/definition.adoc[]
** xref:repositories/create-instances.adoc[]
** xref:keyvalue/repository/map-repositories.adoc[]
** xref:keyvalue/value-expressions.adoc[]
** xref:repositories/query-keywords-reference.adoc[]
** xref:repositories/query-return-types-reference.adoc[]

View File

@@ -56,7 +56,7 @@ template.findAllOf(User.class); <2>
<2> Returns only elements of type `User` stored in `persons` keyspace.
====
TIP: `@KeySpace` supports https://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/core.html#expressions[SpEL] expressions allowing dynamic keyspace configuration.
TIP: `@KeySpace` supports xref:keyvalue/value-expressions.adoc[Value Expressions] allowing dynamic keyspace configuration.
[[key-value.keyspaces-custom]]
=== Custom KeySpace Annotation

View File

@@ -0,0 +1 @@
include::{commons}@data-commons::page$value-expressions.adoc[]

View File

@@ -27,7 +27,7 @@ import org.springframework.data.annotation.Persistent;
/**
* Marker interface for methods with {@link Persistent} annotations indicating the presence of a dedicated keyspace the
* entity should reside in. If present the value will be picked up for resolving the keyspace. The {@link #value()}
* attribute supports SpEL expressions to dynamically resolve the keyspace based on a per-operation basis.
* attribute supports Value Expressions to dynamically resolve the keyspace based on a per-operation basis.
*
* <pre class="code">
* &#64;Persistent

View File

@@ -15,13 +15,15 @@
*/
package org.springframework.data.keyvalue.core.mapping;
import org.springframework.data.expression.ValueExpression;
import org.springframework.data.expression.ValueExpressionParser;
import org.springframework.data.mapping.model.BasicPersistentEntity;
import org.springframework.data.util.TypeInformation;
import org.springframework.expression.Expression;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
@@ -35,9 +37,9 @@ import org.springframework.util.StringUtils;
public class BasicKeyValuePersistentEntity<T, P extends KeyValuePersistentProperty<P>>
extends BasicPersistentEntity<T, P> implements KeyValuePersistentEntity<T, P> {
private static final SpelExpressionParser PARSER = new SpelExpressionParser();
private static final ValueExpressionParser PARSER = ValueExpressionParser.create(SpelExpressionParser::new);
private final @Nullable Expression keyspaceExpression;
private final @Nullable ValueExpression keyspaceExpression;
private final @Nullable String keyspace;
/**
@@ -89,16 +91,16 @@ public class BasicKeyValuePersistentEntity<T, P extends KeyValuePersistentProper
* @return the parsed {@link Expression} or {@literal null}.
*/
@Nullable
private static Expression detectExpression(String potentialExpression) {
private static ValueExpression detectExpression(String potentialExpression) {
Expression expression = PARSER.parseExpression(potentialExpression, ParserContext.TEMPLATE_EXPRESSION);
return expression instanceof LiteralExpression ? null : expression;
ValueExpression expression = PARSER.parse(potentialExpression);
return expression.isLiteral() ? null : expression;
}
@Override
public String getKeySpace() {
return keyspaceExpression == null //
? keyspace //
: keyspaceExpression.getValue(getEvaluationContext(null), String.class);
: ObjectUtils.nullSafeToString(keyspaceExpression.evaluate(getValueEvaluationContext(null)));
}
}

View File

@@ -26,6 +26,7 @@ import org.springframework.data.keyvalue.annotation.KeySpace;
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
import org.springframework.data.spel.ExtensionAwareEvaluationContextProvider;
import org.springframework.data.spel.spi.EvaluationContextExtension;
import org.springframework.mock.env.MockEnvironment;
/**
* Unit tests for {@link BasicKeyValuePersistentEntity}.
@@ -43,14 +44,17 @@ class BasicKeyValuePersistentEntityUnitTests {
.isEqualTo(KeyspaceEntity.class.getName());
}
@Test // DATAKV-268
@Test // DATAKV-268, GH-613
void shouldEvaluateKeyspaceExpression() {
MockEnvironment environment = new MockEnvironment().withProperty("my.property", "foo");
mappingContext.setEnvironment(environment);
KeyValuePersistentEntity<?, ?> persistentEntity = mappingContext.getPersistentEntity(ExpressionEntity.class);
persistentEntity.setEvaluationContextProvider(
new ExtensionAwareEvaluationContextProvider(Collections.singletonList(new SampleExtension())));
assertThat(persistentEntity.getKeySpace()).isEqualTo("some");
assertThat(persistentEntity.getKeySpace()).isEqualTo("some_foo");
}
@Test // DATAKV-268
@@ -81,7 +85,7 @@ class BasicKeyValuePersistentEntityUnitTests {
assertThat(persistentEntity.getKeySpace()).isEqualTo(NoKeyspaceEntity.class.getName());
}
@KeySpace("#{myProperty}")
@KeySpace("#{myProperty}_${my.property}")
private static class ExpressionEntity {}
@KeySpace