diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MappingJdbcConverter.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MappingJdbcConverter.java index 9fd503947..a4cb8e08a 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MappingJdbcConverter.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MappingJdbcConverter.java @@ -26,6 +26,7 @@ import java.util.function.Function; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.context.ApplicationContextAware; import org.springframework.core.convert.ConverterNotFoundException; import org.springframework.core.convert.converter.Converter; @@ -35,7 +36,7 @@ import org.springframework.data.jdbc.core.mapping.JdbcValue; import org.springframework.data.jdbc.support.JdbcUtil; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.SimpleTypeHolder; -import org.springframework.data.mapping.model.SpELExpressionEvaluator; +import org.springframework.data.mapping.model.ValueExpressionEvaluator; import org.springframework.data.relational.core.conversion.MappingRelationalConverter; import org.springframework.data.relational.core.conversion.ObjectPath; import org.springframework.data.relational.core.conversion.RelationalConverter; @@ -289,7 +290,7 @@ public class MappingJdbcConverter extends MappingRelationalConverter implements @Override protected RelationalPropertyValueProvider newValueProvider(RowDocumentAccessor documentAccessor, - SpELExpressionEvaluator evaluator, ConversionContext context) { + ValueExpressionEvaluator evaluator, ConversionContext context) { if (context instanceof ResolvingConversionContext rcc) { diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/MappingRelationalConverter.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/MappingRelationalConverter.java index c239ef173..8a777fc8e 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/MappingRelationalConverter.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/MappingRelationalConverter.java @@ -32,6 +32,9 @@ import org.springframework.core.CollectionFactory; import org.springframework.core.ResolvableType; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.env.Environment; +import org.springframework.core.env.EnvironmentCapable; +import org.springframework.core.env.StandardEnvironment; import org.springframework.data.convert.CustomConversions; import org.springframework.data.mapping.InstanceCreatorMetadata; import org.springframework.data.mapping.MappingException; @@ -41,16 +44,16 @@ import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyAccessor; import org.springframework.data.mapping.PersistentPropertyPathAccessor; 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.SimpleTypeHolder; 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.projection.EntityProjection; import org.springframework.data.projection.EntityProjectionIntrospector; import org.springframework.data.projection.EntityProjectionIntrospector.ProjectionPredicate; @@ -67,6 +70,8 @@ import org.springframework.data.relational.core.sql.SqlIdentifier; import org.springframework.data.relational.domain.RowDocument; import org.springframework.data.util.Predicates; import org.springframework.data.util.TypeInformation; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -84,14 +89,23 @@ import org.springframework.util.ClassUtils; * @see CustomConversions * @since 3.2 */ -public class MappingRelationalConverter extends AbstractRelationalConverter implements ApplicationContextAware { +public class MappingRelationalConverter extends AbstractRelationalConverter + implements ApplicationContextAware, EnvironmentCapable { private SpELContext spELContext; - private final SpelAwareProxyProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory(); + private @Nullable Environment environment; + + private final ExpressionParser expressionParser = new SpelExpressionParser(); + + private final SpelAwareProxyProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory( + expressionParser); private final EntityProjectionIntrospector introspector; + private final CachingValueExpressionEvaluatorFactory valueExpressionEvaluatorFactory = new CachingValueExpressionEvaluatorFactory( + expressionParser, this, o -> spELContext.getEvaluationContext(o)); + /** * Creates a new {@link MappingRelationalConverter} given the new {@link RelationalMappingContext}. * @@ -133,10 +147,20 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.spELContext = new SpELContext(this.spELContext, applicationContext); + this.environment = applicationContext.getEnvironment(); this.projectionFactory.setBeanFactory(applicationContext); this.projectionFactory.setBeanClassLoader(applicationContext.getClassLoader()); } + @Override + public Environment getEnvironment() { + + if (this.environment == null) { + this.environment = new StandardEnvironment(); + } + return this.environment; + } + /** * Creates a new {@link ConversionContext}. * @@ -196,7 +220,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl TypeInformation mappedType = projection.getActualMappedType(); RelationalPersistentEntity mappedEntity = (RelationalPersistentEntity) getMappingContext() .getPersistentEntity(mappedType); - SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(document, spELContext); + ValueExpressionEvaluator evaluator = valueExpressionEvaluatorFactory.create(document); boolean isInterfaceProjection = mappedType.getType().isInterface(); if (isInterfaceProjection) { @@ -432,7 +456,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl private S read(ConversionContext context, RelationalPersistentEntity entity, RowDocumentAccessor documentAccessor) { - SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(documentAccessor.getDocument(), spELContext); + ValueExpressionEvaluator evaluator = valueExpressionEvaluatorFactory.create(documentAccessor.getDocument()); InstanceCreatorMetadata instanceCreatorMetadata = entity.getInstanceCreatorMetadata(); @@ -455,7 +479,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl } private ParameterValueProvider getParameterProvider(ConversionContext context, - RelationalPersistentEntity entity, RowDocumentAccessor source, SpELExpressionEvaluator evaluator) { + RelationalPersistentEntity entity, RowDocumentAccessor source, ValueExpressionEvaluator evaluator) { // Ensure that ConversionContext is contextualized to the current property. RelationalPropertyValueProvider contextualizing = new RelationalPropertyValueProvider() { @@ -489,12 +513,12 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl PersistentEntityParameterValueProvider parameterProvider = new PersistentEntityParameterValueProvider<>( entity, contextualizing, context.getPath().getCurrentObject()); - return new ConverterAwareSpELExpressionParameterValueProvider(context, evaluator, getConversionService(), + return new ConverterAwareExpressionParameterValueProvider(context, evaluator, getConversionService(), new ConvertingParameterValueProvider<>(parameterProvider::getParameterValue)); } private S populateProperties(ConversionContext context, RelationalPersistentEntity entity, - RowDocumentAccessor documentAccessor, SpELExpressionEvaluator evaluator, S instance) { + RowDocumentAccessor documentAccessor, ValueExpressionEvaluator evaluator, S instance) { if (!entity.requiresPropertyPopulation()) { return instance; @@ -516,7 +540,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl } protected RelationalPropertyValueProvider newValueProvider(RowDocumentAccessor documentAccessor, - SpELExpressionEvaluator evaluator, ConversionContext context) { + ValueExpressionEvaluator evaluator, ConversionContext context) { return new DocumentValueProvider(context, documentAccessor, evaluator, spELContext); } @@ -1059,22 +1083,22 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl private final ConversionContext context; private final RowDocumentAccessor accessor; - private final SpELExpressionEvaluator evaluator; + private final ValueExpressionEvaluator evaluator; private final SpELContext spELContext; /** - * Creates a new {@link RelationalPropertyValueProvider} for the given source and {@link SpELExpressionEvaluator}. + * Creates a new {@link RelationalPropertyValueProvider} for the given source and {@link ValueExpressionEvaluator}. * * @param context must not be {@literal null}. * @param accessor must not be {@literal null}. * @param evaluator must not be {@literal null}. */ private DocumentValueProvider(ConversionContext context, RowDocumentAccessor 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; this.evaluator = evaluator; @@ -1166,24 +1190,24 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl } /** - * Extension of {@link SpELExpressionParameterValueProvider} to recursively trigger value conversion on the raw + * Extension of {@link ValueExpressionParameterValueProvider} to recursively trigger value conversion on the raw * resolved SpEL value. */ - private static class ConverterAwareSpELExpressionParameterValueProvider - extends SpELExpressionParameterValueProvider { + private static class ConverterAwareExpressionParameterValueProvider + extends ValueExpressionParameterValueProvider { private final ConversionContext context; /** - * Creates a new {@link ConverterAwareSpELExpressionParameterValueProvider}. + * Creates a new {@link ConverterAwareExpressionParameterValueProvider}. * * @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 ConverterAwareExpressionParameterValueProvider(ConversionContext context, ValueExpressionEvaluator evaluator, + ConversionService conversionService, ParameterValueProvider delegate) { super(evaluator, conversionService, delegate); @@ -1194,9 +1218,11 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl } @Override - protected T potentiallyConvertSpelValue(Object object, Parameter parameter) { + protected T potentiallyConvertExpressionValue(Object object, + Parameter parameter) { return context.convert(object, parameter.getType()); } + } private record PropertyTranslatingPropertyAccessor(PersistentPropertyAccessor delegate,