Add support for Value Expressions.

Closes: #4634
Original Pull Request: #4635
This commit is contained in:
Mark Paluch
2024-02-12 15:44:39 +01:00
committed by Christoph Strobl
parent 374ebb801b
commit e6dd5a3565
12 changed files with 134 additions and 63 deletions

View File

@@ -15,12 +15,14 @@
*/
package org.springframework.data.mongodb.core.convert;
import java.util.function.Function;
import org.bson.Document;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
import org.springframework.data.mapping.model.SpELContext;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.lang.Nullable;
@@ -37,6 +39,7 @@ class DefaultDbRefProxyHandler implements DbRefProxyHandler {
private final SpELContext spELContext;
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
private final ValueResolver resolver;
private final Function<Object, ValueExpressionEvaluator> evaluatorFactory;
/**
* @param spELContext must not be {@literal null}.
@@ -45,11 +48,12 @@ class DefaultDbRefProxyHandler implements DbRefProxyHandler {
*/
public DefaultDbRefProxyHandler(SpELContext spELContext,
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext,
ValueResolver resolver) {
ValueResolver resolver, Function<Object, ValueExpressionEvaluator> evaluatorFactory) {
this.spELContext = spELContext;
this.mappingContext = mappingContext;
this.resolver = resolver;
this.evaluatorFactory = evaluatorFactory;
}
@Override
@@ -66,7 +70,7 @@ class DefaultDbRefProxyHandler implements DbRefProxyHandler {
return proxy;
}
SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(proxy, spELContext);
ValueExpressionEvaluator evaluator = evaluatorFactory.apply(proxy);
PersistentPropertyAccessor accessor = entity.getPropertyAccessor(proxy);
Document object = new Document(idProperty.getFieldName(), source.getId());

View File

@@ -17,7 +17,7 @@ package org.springframework.data.mongodb.core.convert;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
/**
@@ -32,18 +32,18 @@ class DefaultDbRefResolverCallback implements DbRefResolverCallback {
private final Bson surroundingObject;
private final ObjectPath path;
private final ValueResolver resolver;
private final SpELExpressionEvaluator evaluator;
private final ValueExpressionEvaluator evaluator;
/**
* Creates a new {@link DefaultDbRefResolverCallback} using the given {@link Document}, {@link ObjectPath},
* {@link ValueResolver} and {@link SpELExpressionEvaluator}.
* {@link ValueResolver} and {@link ValueExpressionEvaluator}.
*
* @param surroundingObject must not be {@literal null}.
* @param path must not be {@literal null}.
* @param evaluator must not be {@literal null}.
* @param resolver must not be {@literal null}.
*/
public DefaultDbRefResolverCallback(Bson surroundingObject, ObjectPath path, SpELExpressionEvaluator evaluator,
public DefaultDbRefResolverCallback(Bson surroundingObject, ObjectPath path, ValueExpressionEvaluator evaluator,
ValueResolver resolver) {
this.surroundingObject = surroundingObject;

View File

@@ -39,6 +39,7 @@ import org.bson.codecs.configuration.CodecRegistry;
import org.bson.conversions.Bson;
import org.bson.json.JsonReader;
import org.bson.types.ObjectId;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.context.ApplicationContext;
@@ -47,6 +48,9 @@ import org.springframework.core.CollectionFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.Environment;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.data.annotation.Reference;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.convert.TypeMapper;
@@ -59,15 +63,16 @@ import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.callback.EntityCallbacks;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.CachingValueExpressionEvaluatorFactory;
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
import org.springframework.data.mapping.model.EntityInstantiator;
import org.springframework.data.mapping.model.ParameterValueProvider;
import org.springframework.data.mapping.model.PersistentEntityParameterValueProvider;
import org.springframework.data.mapping.model.PropertyValueProvider;
import org.springframework.data.mapping.model.SpELContext;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.mapping.model.SpELExpressionParameterValueProvider;
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
import org.springframework.data.mapping.model.ValueExpressionParameterValueProvider;
import org.springframework.data.mongodb.CodecRegistryProvider;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentProperty;
@@ -88,6 +93,7 @@ import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.util.Predicates;
import org.springframework.data.util.TypeInformation;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -116,7 +122,8 @@ import com.mongodb.DBRef;
* @author Divya Srivastava
* @author Julia Lee
*/
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware {
public class MappingMongoConverter extends AbstractMongoConverter
implements ApplicationContextAware, EnvironmentCapable {
private static final String INCOMPATIBLE_TYPES = "Cannot convert %1$s of type %2$s into an instance of %3$s; Implement a custom Converter<%2$s, %3$s> and register it with the CustomConversions; Parent object was: %4$s";
private static final String INVALID_TYPE_TO_READ = "Expected to read Document %s into type %s but didn't find a PersistentEntity for the latter";
@@ -132,6 +139,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
protected final ReferenceLookupDelegate referenceLookupDelegate;
protected @Nullable ApplicationContext applicationContext;
protected @Nullable Environment environment;
protected MongoTypeMapper typeMapper;
protected @Nullable String mapKeyDotReplacement = null;
protected @Nullable CodecRegistryProvider codecRegistryProvider;
@@ -139,8 +147,12 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
private MongoTypeMapper defaultTypeMapper;
private SpELContext spELContext;
private @Nullable EntityCallbacks entityCallbacks;
private final SpelExpressionParser expressionParser = new SpelExpressionParser();
private final DocumentPointerFactory documentPointerFactory;
private final SpelAwareProxyProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory();
private final SpelAwareProxyProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory(
expressionParser);
private final CachingValueExpressionEvaluatorFactory expressionEvaluatorFactory = new CachingValueExpressionEvaluatorFactory(
expressionParser, this, o -> spELContext.getEvaluationContext(o));
/**
* Creates a new {@link MappingMongoConverter} given the new {@link DbRefResolver} and {@link MappingContext}.
@@ -169,7 +181,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
ConversionContext context = getConversionContext(path);
return MappingMongoConverter.this.getValueInternal(context, prop, bson, evaluator);
});
}, expressionEvaluatorFactory::create);
this.referenceLookupDelegate = new ReferenceLookupDelegate(mappingContext, spELContext);
this.documentPointerFactory = new DocumentPointerFactory(conversionService, mappingContext);
@@ -271,9 +283,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return mappingContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
this.environment = applicationContext.getEnvironment();
this.spELContext = new SpELContext(this.spELContext, applicationContext);
this.projectionFactory.setBeanFactory(applicationContext);
this.projectionFactory.setBeanClassLoader(applicationContext.getClassLoader());
@@ -288,6 +302,15 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
}
@Override
public Environment getEnvironment() {
if (environment == null) {
environment = new StandardEnvironment();
}
return environment;
}
/**
* Set the {@link EntityCallbacks} instance to use when invoking
* {@link org.springframework.data.mapping.callback.EntityCallback callbacks} like the {@link AfterConvertCallback}.
@@ -328,7 +351,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
TypeInformation<?> mappedType = projection.getActualMappedType();
MongoPersistentEntity<R> mappedEntity = (MongoPersistentEntity<R>) getMappingContext()
.getPersistentEntity(mappedType);
SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(bson, spELContext);
ValueExpressionEvaluator evaluator = expressionEvaluatorFactory.create(bson);
boolean isInterfaceProjection = mappedType.getType().isInterface();
if (isInterfaceProjection) {
@@ -481,14 +504,14 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
private ParameterValueProvider<MongoPersistentProperty> getParameterProvider(ConversionContext context,
MongoPersistentEntity<?> entity, DocumentAccessor source, SpELExpressionEvaluator evaluator) {
MongoPersistentEntity<?> entity, DocumentAccessor source, ValueExpressionEvaluator evaluator) {
AssociationAwareMongoDbPropertyValueProvider provider = new AssociationAwareMongoDbPropertyValueProvider(context,
source, evaluator);
PersistentEntityParameterValueProvider<MongoPersistentProperty> parameterProvider = new PersistentEntityParameterValueProvider<>(
entity, provider, context.getPath().getCurrentObject());
return new ConverterAwareSpELExpressionParameterValueProvider(context, evaluator, conversionService,
return new ConverterAwareValueExpressionParameterValueProvider(context, evaluator, conversionService,
parameterProvider);
}
@@ -499,7 +522,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return existing;
}
SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(bson, spELContext);
ValueExpressionEvaluator evaluator = expressionEvaluatorFactory.create(bson);
DocumentAccessor documentAccessor = new DocumentAccessor(bson);
InstanceCreatorMetadata<MongoPersistentProperty> instanceCreatorMetadata = entity.getInstanceCreatorMetadata();
@@ -515,7 +538,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
private <S> S populateProperties(ConversionContext context, MongoPersistentEntity<S> entity,
DocumentAccessor documentAccessor, SpELExpressionEvaluator evaluator, S instance) {
DocumentAccessor documentAccessor, ValueExpressionEvaluator evaluator, S instance) {
if (!entity.requiresPropertyPopulation()) {
return instance;
@@ -545,7 +568,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
*/
@Nullable
private Object readAndPopulateIdentifier(ConversionContext context, PersistentPropertyAccessor<?> accessor,
DocumentAccessor document, MongoPersistentEntity<?> entity, SpELExpressionEvaluator evaluator) {
DocumentAccessor document, MongoPersistentEntity<?> entity, ValueExpressionEvaluator evaluator) {
Object rawId = document.getRawId(entity);
@@ -565,7 +588,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
@Nullable
private Object readIdValue(ConversionContext context, SpELExpressionEvaluator evaluator,
private Object readIdValue(ConversionContext context, ValueExpressionEvaluator evaluator,
MongoPersistentProperty idProperty, Object rawId) {
String expression = idProperty.getSpelExpression();
@@ -578,7 +601,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
private void readProperties(ConversionContext context, MongoPersistentEntity<?> entity,
PersistentPropertyAccessor<?> accessor, DocumentAccessor documentAccessor,
MongoDbPropertyValueProvider valueProvider, SpELExpressionEvaluator evaluator,
MongoDbPropertyValueProvider valueProvider, ValueExpressionEvaluator evaluator,
Predicate<MongoPersistentProperty> propertyFilter) {
DbRefResolverCallback callback = null;
@@ -622,7 +645,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
private DbRefResolverCallback getDbRefResolverCallback(ConversionContext context, DocumentAccessor documentAccessor,
SpELExpressionEvaluator evaluator) {
ValueExpressionEvaluator evaluator) {
return new DefaultDbRefResolverCallback(documentAccessor.getDocument(), context.getPath(), evaluator,
(prop, bson, e, path) -> MappingMongoConverter.this.getValueInternal(context, prop, bson, e));
@@ -1387,7 +1410,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
@Nullable
private Object getValueInternal(ConversionContext context, MongoPersistentProperty prop, Bson bson,
SpELExpressionEvaluator evaluator) {
ValueExpressionEvaluator evaluator) {
return new MongoDbPropertyValueProvider(context, bson, evaluator).getPropertyValue(prop);
}
@@ -1876,23 +1899,23 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
final ConversionContext context;
final DocumentAccessor accessor;
final SpELExpressionEvaluator evaluator;
final ValueExpressionEvaluator evaluator;
final SpELContext spELContext;
/**
* Creates a new {@link MongoDbPropertyValueProvider} for the given source, {@link SpELExpressionEvaluator} and
* Creates a new {@link MongoDbPropertyValueProvider} for the given source, {@link ValueExpressionEvaluator} and
* {@link ObjectPath}.
*
* @param context must not be {@literal null}.
* @param source must not be {@literal null}.
* @param evaluator must not be {@literal null}.
*/
MongoDbPropertyValueProvider(ConversionContext context, Bson source, SpELExpressionEvaluator evaluator) {
MongoDbPropertyValueProvider(ConversionContext context, Bson source, ValueExpressionEvaluator evaluator) {
this(context, new DocumentAccessor(source), evaluator, null);
}
/**
* Creates a new {@link MongoDbPropertyValueProvider} for the given source, {@link SpELExpressionEvaluator} and
* Creates a new {@link MongoDbPropertyValueProvider} for the given source, {@link ValueExpressionEvaluator} and
* {@link ObjectPath}.
*
* @param context must not be {@literal null}.
@@ -1900,11 +1923,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
* @param evaluator must not be {@literal null}.
*/
MongoDbPropertyValueProvider(ConversionContext context, DocumentAccessor accessor,
SpELExpressionEvaluator evaluator, SpELContext spELContext) {
ValueExpressionEvaluator evaluator, SpELContext spELContext) {
Assert.notNull(context, "ConversionContext must no be null");
Assert.notNull(accessor, "DocumentAccessor must no be null");
Assert.notNull(evaluator, "SpELExpressionEvaluator must not be null");
Assert.notNull(evaluator, "ValueExpressionEvaluator must not be null");
this.context = context;
this.accessor = accessor;
@@ -1953,13 +1976,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
/**
* Creates a new {@link AssociationAwareMongoDbPropertyValueProvider} for the given source,
* {@link SpELExpressionEvaluator} and {@link ObjectPath}.
* {@link ValueExpressionEvaluator} and {@link ObjectPath}.
*
* @param source must not be {@literal null}.
* @param evaluator must not be {@literal null}.
*/
AssociationAwareMongoDbPropertyValueProvider(ConversionContext context, DocumentAccessor source,
SpELExpressionEvaluator evaluator) {
ValueExpressionEvaluator evaluator) {
super(context, source, evaluator, MappingMongoConverter.this.spELContext);
}
@@ -2000,21 +2023,21 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
*
* @author Oliver Gierke
*/
private static class ConverterAwareSpELExpressionParameterValueProvider
extends SpELExpressionParameterValueProvider<MongoPersistentProperty> {
private static class ConverterAwareValueExpressionParameterValueProvider
extends ValueExpressionParameterValueProvider<MongoPersistentProperty> {
private final ConversionContext context;
/**
* Creates a new {@link ConverterAwareSpELExpressionParameterValueProvider}.
* Creates a new {@link ConverterAwareValueExpressionParameterValueProvider}.
*
* @param context must not be {@literal null}.
* @param evaluator must not be {@literal null}.
* @param conversionService must not be {@literal null}.
* @param delegate must not be {@literal null}.
*/
public ConverterAwareSpELExpressionParameterValueProvider(ConversionContext context,
SpELExpressionEvaluator evaluator, ConversionService conversionService,
public ConverterAwareValueExpressionParameterValueProvider(ConversionContext context,
ValueExpressionEvaluator evaluator, ConversionService conversionService,
ParameterValueProvider<MongoPersistentProperty> delegate) {
super(evaluator, conversionService, delegate);
@@ -2025,7 +2048,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
@Override
protected <T> T potentiallyConvertSpelValue(Object object, Parameter<T, MongoPersistentProperty> parameter) {
protected <T> T potentiallyConvertExpressionValue(Object object, Parameter<T, MongoPersistentProperty> parameter) {
return context.convert(object, parameter.getType());
}
}

View File

@@ -16,6 +16,7 @@
package org.springframework.data.mongodb.core.convert;
import org.bson.conversions.Bson;
import org.springframework.data.convert.ValueConversionContext;
import org.springframework.data.mapping.model.PropertyValueProvider;
import org.springframework.data.mapping.model.SpELContext;

View File

@@ -17,7 +17,8 @@ package org.springframework.data.mongodb.core.convert;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.lang.Nullable;
@@ -32,7 +33,7 @@ interface ValueResolver {
/**
* Resolves the value for the given {@link MongoPersistentProperty} within the given {@link Document} using the given
* {@link SpELExpressionEvaluator} and {@link ObjectPath}.
* {@link ValueExpressionEvaluator} and {@link ObjectPath}.
*
* @param prop
* @param bson
@@ -41,5 +42,5 @@ interface ValueResolver {
* @return
*/
@Nullable
Object getValueInternal(MongoPersistentProperty prop, Bson bson, SpELExpressionEvaluator evaluator, ObjectPath path);
Object getValueInternal(MongoPersistentProperty prop, Bson bson, ValueExpressionEvaluator evaluator, ObjectPath path);
}

View File

@@ -26,6 +26,9 @@ import java.util.List;
import java.util.Map;
import org.springframework.data.annotation.Id;
import org.springframework.data.expression.ValueEvaluationContext;
import org.springframework.data.expression.ValueExpression;
import org.springframework.data.expression.ValueExpressionParser;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.AssociationHandler;
import org.springframework.data.mapping.MappingException;
@@ -38,8 +41,6 @@ import org.springframework.data.util.Lazy;
import org.springframework.data.util.TypeInformation;
import org.springframework.expression.EvaluationContext;
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.Assert;
@@ -61,15 +62,15 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
implements MongoPersistentEntity<T> {
private static final String AMBIGUOUS_FIELD_MAPPING = "Ambiguous field mapping detected; Both %s and %s map to the same field name %s; Disambiguate using @Field annotation";
private static final SpelExpressionParser PARSER = new SpelExpressionParser();
private static final ValueExpressionParser PARSER = ValueExpressionParser.create(SpelExpressionParser::new);
private final String collection;
private final String language;
private final @Nullable Expression expression;
private final @Nullable ValueExpression expression;
private final @Nullable String collation;
private final @Nullable Expression collationExpression;
private final @Nullable ValueExpression collationExpression;
private final ShardKey shardKey;
@@ -125,11 +126,12 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
return sharded.immutableKey() ? ShardKey.immutable(shardKey) : shardKey;
}
@Override
public String getCollection() {
return expression == null //
? collection //
: expression.getValue(getEvaluationContext(null), String.class);
: ObjectUtils.nullSafeToString(expression.evaluate(getValueEvaluationContext(null)));
}
@Override
@@ -152,7 +154,7 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
public org.springframework.data.mongodb.core.query.Collation getCollation() {
Object collationValue = collationExpression != null
? collationExpression.getValue(getEvaluationContext(null), String.class)
? collationExpression.evaluate(getValueEvaluationContext(null))
: this.collation;
if (collationValue == null) {
@@ -196,6 +198,16 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
return super.getEvaluationContext(rootObject, dependencies);
}
@Override
public ValueEvaluationContext getValueEvaluationContext(Object rootObject) {
return super.getValueEvaluationContext(rootObject);
}
@Override
public ValueEvaluationContext getValueEvaluationContext(Object rootObject, ExpressionDependencies dependencies) {
return super.getValueEvaluationContext(rootObject, dependencies);
}
private void verifyFieldUniqueness() {
AssertFieldNameUniquenessHandler handler = new AssertFieldNameUniquenessHandler();
@@ -290,21 +302,21 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
}
/**
* Returns a SpEL {@link Expression} if the given {@link String} is actually an expression that does not evaluate to a
* {@link LiteralExpression} (indicating that no subsequent evaluation is necessary).
* Returns a Value {@link Expression} if the given {@link String} is actually an expression that does not evaluate to
* a literal expression (indicating that no subsequent evaluation is necessary).
*
* @param potentialExpression can be {@literal null}
* @return can be {@literal null}.
*/
@Nullable
private static Expression detectExpression(@Nullable String potentialExpression) {
private static ValueExpression detectExpression(@Nullable String potentialExpression) {
if (!StringUtils.hasText(potentialExpression)) {
return null;
}
Expression expression = PARSER.parseExpression(potentialExpression, ParserContext.TEMPLATE_EXPRESSION);
return expression instanceof LiteralExpression ? null : expression;
ValueExpression expression = PARSER.parse(potentialExpression);
return expression.isLiteral() ? null : expression;
}
/**
@@ -332,8 +344,7 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
MongoPersistentProperty existingProperty = properties.get(fieldName);
if (existingProperty != null) {
throw new MappingException(
String.format(AMBIGUOUS_FIELD_MAPPING, property, existingProperty, fieldName));
throw new MappingException(String.format(AMBIGUOUS_FIELD_MAPPING, property, existingProperty, fieldName));
}
properties.put(fieldName, property);
@@ -398,9 +409,9 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
if (persistentProperty.isDbReference() && persistentProperty.getDBRef().lazy()) {
if (persistentProperty.isArray() || Modifier.isFinal(persistentProperty.getActualType().getModifiers())) {
throw new MappingException(String.format(
"Invalid lazy DBRef property for %s; Found %s which must not be an array nor a final class",
persistentProperty.getField(), persistentProperty.getActualType()));
throw new MappingException(
String.format("Invalid lazy DBRef property for %s; Found %s which must not be an array nor a final class",
persistentProperty.getField(), persistentProperty.getActualType()));
}
}
}

View File

@@ -23,6 +23,9 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.data.expression.ValueEvaluationContext;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.MappingException;
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
@@ -230,6 +233,25 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
return rootObject != null ? new StandardEvaluationContext(rootObject) : new StandardEvaluationContext();
}
/**
* Obtain the {@link EvaluationContext} for a specific root object.
*
* @param rootObject can be {@literal null}.
* @return never {@literal null}.
* @since 3.3
*/
public ValueEvaluationContext getValueEvaluationContext(@Nullable Object rootObject) {
if (getOwner() instanceof BasicMongoPersistentEntity mongoPersistentEntity) {
return mongoPersistentEntity.getValueEvaluationContext(rootObject);
}
StandardEvaluationContext standardEvaluationContext = rootObject != null ? new StandardEvaluationContext(rootObject)
: new StandardEvaluationContext();
return ValueEvaluationContext.of(new StandardEnvironment(), standardEvaluationContext);
}
@Override
public MongoField getMongoField() {
return doGetMongoField();
@@ -318,7 +340,7 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
String annotatedName = getAnnotatedFieldName();
if (!ID_FIELD_NAME.equals(annotatedName)) {
if(LOG.isWarnEnabled()) {
if (LOG.isWarnEnabled()) {
LOG.warn(String.format(
"Customizing field name for id property '%s.%s' is not allowed; Custom name ('%s') will not be considered",
getOwner().getName(), getName(), annotatedName));

View File

@@ -24,6 +24,7 @@ import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.springframework.core.env.Environment;
import org.springframework.data.mapping.*;
import org.springframework.data.mapping.model.PersistentPropertyAccessorFactory;
import org.springframework.data.mongodb.core.query.Collation;
@@ -326,6 +327,11 @@ class UnwrappedMongoPersistentEntity<T> implements MongoPersistentEntity<T> {
}
@Override
public void setEnvironment(Environment environment) {
}
@Override
public boolean isUnwrapped() {
return context.getProperty().isUnwrapped();

View File

@@ -19,7 +19,7 @@ import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
import org.springframework.data.spel.ExpressionDependencies;
import org.springframework.data.util.Lazy;
import org.springframework.expression.EvaluationContext;
@@ -39,7 +39,7 @@ import org.springframework.lang.Nullable;
public class ParameterBindingContext {
private final ValueProvider valueProvider;
private final SpELExpressionEvaluator expressionEvaluator;
private final ValueExpressionEvaluator expressionEvaluator;
/**
* @param valueProvider
@@ -67,7 +67,7 @@ public class ParameterBindingContext {
* @param expressionEvaluator
* @since 3.1
*/
public ParameterBindingContext(ValueProvider valueProvider, SpELExpressionEvaluator expressionEvaluator) {
public ParameterBindingContext(ValueProvider valueProvider, ValueExpressionEvaluator expressionEvaluator) {
this.valueProvider = valueProvider;
this.expressionEvaluator = expressionEvaluator;
}

View File

@@ -40,7 +40,8 @@ import org.bson.Transformer;
import org.bson.codecs.*;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.json.JsonParseException;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
import org.springframework.data.mongodb.core.mapping.FieldName;
import org.springframework.data.spel.EvaluationContextProvider;
import org.springframework.data.spel.ExpressionDependencies;
@@ -384,7 +385,7 @@ public class ParameterBindingDocumentCodec implements CollectibleCodec<Document>
* @author Christoph Strobl
* @since 3.1
*/
static class DependencyCapturingExpressionEvaluator implements SpELExpressionEvaluator {
static class DependencyCapturingExpressionEvaluator implements ValueExpressionEvaluator {
private static final Object PLACEHOLDER = new Object();

View File

@@ -26,6 +26,7 @@
*** xref:mongodb/mapping/document-references.adoc[Object References]
*** xref:mongodb/mapping/mapping-index-management.adoc[]
** xref:mongodb/value-expressions.adoc[]
** xref:mongodb/lifecycle-events.adoc[]
** xref:mongodb/auditing.adoc[]
** xref:mongodb/client-session-transactions.adoc[]

View File

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