Add support for Value Expressions.
Closes: #4634 Original Pull Request: #4635
This commit is contained in:
committed by
Christoph Strobl
parent
374ebb801b
commit
e6dd5a3565
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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[]
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
include::{commons}@data-commons::page$value-expressions.adoc[]
|
||||
Reference in New Issue
Block a user