Browse Source

Add support for ValueExpression.

Closes #1738
pull/1746/head
Mark Paluch 2 years ago
parent
commit
7ac5c6601b
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 5
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MappingJdbcConverter.java
  2. 70
      spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/MappingRelationalConverter.java

5
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.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
import org.springframework.core.convert.ConverterNotFoundException; import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.converter.Converter; 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.jdbc.support.JdbcUtil;
import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.SimpleTypeHolder; 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.MappingRelationalConverter;
import org.springframework.data.relational.core.conversion.ObjectPath; import org.springframework.data.relational.core.conversion.ObjectPath;
import org.springframework.data.relational.core.conversion.RelationalConverter; import org.springframework.data.relational.core.conversion.RelationalConverter;
@ -289,7 +290,7 @@ public class MappingJdbcConverter extends MappingRelationalConverter implements
@Override @Override
protected RelationalPropertyValueProvider newValueProvider(RowDocumentAccessor documentAccessor, protected RelationalPropertyValueProvider newValueProvider(RowDocumentAccessor documentAccessor,
SpELExpressionEvaluator evaluator, ConversionContext context) { ValueExpressionEvaluator evaluator, ConversionContext context) {
if (context instanceof ResolvingConversionContext rcc) { if (context instanceof ResolvingConversionContext rcc) {

70
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.ResolvableType;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor; 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.convert.CustomConversions;
import org.springframework.data.mapping.InstanceCreatorMetadata; import org.springframework.data.mapping.InstanceCreatorMetadata;
import org.springframework.data.mapping.MappingException; 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.PersistentPropertyAccessor;
import org.springframework.data.mapping.PersistentPropertyPathAccessor; import org.springframework.data.mapping.PersistentPropertyPathAccessor;
import org.springframework.data.mapping.context.MappingContext; 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.ConvertingPropertyAccessor;
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
import org.springframework.data.mapping.model.EntityInstantiator; import org.springframework.data.mapping.model.EntityInstantiator;
import org.springframework.data.mapping.model.ParameterValueProvider; import org.springframework.data.mapping.model.ParameterValueProvider;
import org.springframework.data.mapping.model.PersistentEntityParameterValueProvider; import org.springframework.data.mapping.model.PersistentEntityParameterValueProvider;
import org.springframework.data.mapping.model.PropertyValueProvider; import org.springframework.data.mapping.model.PropertyValueProvider;
import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.mapping.model.SpELContext; 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.mapping.model.SpELExpressionParameterValueProvider; import org.springframework.data.mapping.model.ValueExpressionParameterValueProvider;
import org.springframework.data.projection.EntityProjection; import org.springframework.data.projection.EntityProjection;
import org.springframework.data.projection.EntityProjectionIntrospector; import org.springframework.data.projection.EntityProjectionIntrospector;
import org.springframework.data.projection.EntityProjectionIntrospector.ProjectionPredicate; 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.relational.domain.RowDocument;
import org.springframework.data.util.Predicates; import org.springframework.data.util.Predicates;
import org.springframework.data.util.TypeInformation; 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.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
@ -84,14 +89,23 @@ import org.springframework.util.ClassUtils;
* @see CustomConversions * @see CustomConversions
* @since 3.2 * @since 3.2
*/ */
public class MappingRelationalConverter extends AbstractRelationalConverter implements ApplicationContextAware { public class MappingRelationalConverter extends AbstractRelationalConverter
implements ApplicationContextAware, EnvironmentCapable {
private SpELContext spELContext; 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 EntityProjectionIntrospector introspector;
private final CachingValueExpressionEvaluatorFactory valueExpressionEvaluatorFactory = new CachingValueExpressionEvaluatorFactory(
expressionParser, this, o -> spELContext.getEvaluationContext(o));
/** /**
* Creates a new {@link MappingRelationalConverter} given the new {@link RelationalMappingContext}. * 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 { public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.spELContext = new SpELContext(this.spELContext, applicationContext); this.spELContext = new SpELContext(this.spELContext, applicationContext);
this.environment = applicationContext.getEnvironment();
this.projectionFactory.setBeanFactory(applicationContext); this.projectionFactory.setBeanFactory(applicationContext);
this.projectionFactory.setBeanClassLoader(applicationContext.getClassLoader()); 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}. * Creates a new {@link ConversionContext}.
* *
@ -196,7 +220,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl
TypeInformation<?> mappedType = projection.getActualMappedType(); TypeInformation<?> mappedType = projection.getActualMappedType();
RelationalPersistentEntity<R> mappedEntity = (RelationalPersistentEntity<R>) getMappingContext() RelationalPersistentEntity<R> mappedEntity = (RelationalPersistentEntity<R>) getMappingContext()
.getPersistentEntity(mappedType); .getPersistentEntity(mappedType);
SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(document, spELContext); ValueExpressionEvaluator evaluator = valueExpressionEvaluatorFactory.create(document);
boolean isInterfaceProjection = mappedType.getType().isInterface(); boolean isInterfaceProjection = mappedType.getType().isInterface();
if (isInterfaceProjection) { if (isInterfaceProjection) {
@ -432,7 +456,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl
private <S> S read(ConversionContext context, RelationalPersistentEntity<S> entity, private <S> S read(ConversionContext context, RelationalPersistentEntity<S> entity,
RowDocumentAccessor documentAccessor) { RowDocumentAccessor documentAccessor) {
SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(documentAccessor.getDocument(), spELContext); ValueExpressionEvaluator evaluator = valueExpressionEvaluatorFactory.create(documentAccessor.getDocument());
InstanceCreatorMetadata<RelationalPersistentProperty> instanceCreatorMetadata = entity.getInstanceCreatorMetadata(); InstanceCreatorMetadata<RelationalPersistentProperty> instanceCreatorMetadata = entity.getInstanceCreatorMetadata();
@ -455,7 +479,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl
} }
private ParameterValueProvider<RelationalPersistentProperty> getParameterProvider(ConversionContext context, private ParameterValueProvider<RelationalPersistentProperty> getParameterProvider(ConversionContext context,
RelationalPersistentEntity<?> entity, RowDocumentAccessor source, SpELExpressionEvaluator evaluator) { RelationalPersistentEntity<?> entity, RowDocumentAccessor source, ValueExpressionEvaluator evaluator) {
// Ensure that ConversionContext is contextualized to the current property. // Ensure that ConversionContext is contextualized to the current property.
RelationalPropertyValueProvider contextualizing = new RelationalPropertyValueProvider() { RelationalPropertyValueProvider contextualizing = new RelationalPropertyValueProvider() {
@ -489,12 +513,12 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl
PersistentEntityParameterValueProvider<RelationalPersistentProperty> parameterProvider = new PersistentEntityParameterValueProvider<>( PersistentEntityParameterValueProvider<RelationalPersistentProperty> parameterProvider = new PersistentEntityParameterValueProvider<>(
entity, contextualizing, context.getPath().getCurrentObject()); entity, contextualizing, context.getPath().getCurrentObject());
return new ConverterAwareSpELExpressionParameterValueProvider(context, evaluator, getConversionService(), return new ConverterAwareExpressionParameterValueProvider(context, evaluator, getConversionService(),
new ConvertingParameterValueProvider<>(parameterProvider::getParameterValue)); new ConvertingParameterValueProvider<>(parameterProvider::getParameterValue));
} }
private <S> S populateProperties(ConversionContext context, RelationalPersistentEntity<S> entity, private <S> S populateProperties(ConversionContext context, RelationalPersistentEntity<S> entity,
RowDocumentAccessor documentAccessor, SpELExpressionEvaluator evaluator, S instance) { RowDocumentAccessor documentAccessor, ValueExpressionEvaluator evaluator, S instance) {
if (!entity.requiresPropertyPopulation()) { if (!entity.requiresPropertyPopulation()) {
return instance; return instance;
@ -516,7 +540,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl
} }
protected RelationalPropertyValueProvider newValueProvider(RowDocumentAccessor documentAccessor, protected RelationalPropertyValueProvider newValueProvider(RowDocumentAccessor documentAccessor,
SpELExpressionEvaluator evaluator, ConversionContext context) { ValueExpressionEvaluator evaluator, ConversionContext context) {
return new DocumentValueProvider(context, documentAccessor, evaluator, spELContext); return new DocumentValueProvider(context, documentAccessor, evaluator, spELContext);
} }
@ -1059,22 +1083,22 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl
private final ConversionContext context; private final ConversionContext context;
private final RowDocumentAccessor accessor; private final RowDocumentAccessor accessor;
private final SpELExpressionEvaluator evaluator; private final ValueExpressionEvaluator evaluator;
private final SpELContext spELContext; 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 context must not be {@literal null}.
* @param accessor must not be {@literal null}. * @param accessor must not be {@literal null}.
* @param evaluator must not be {@literal null}. * @param evaluator must not be {@literal null}.
*/ */
private DocumentValueProvider(ConversionContext context, RowDocumentAccessor accessor, private DocumentValueProvider(ConversionContext context, RowDocumentAccessor accessor,
SpELExpressionEvaluator evaluator, SpELContext spELContext) { ValueExpressionEvaluator evaluator, SpELContext spELContext) {
Assert.notNull(context, "ConversionContext must no be null"); Assert.notNull(context, "ConversionContext must no be null");
Assert.notNull(accessor, "DocumentAccessor 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.context = context;
this.accessor = accessor; this.accessor = accessor;
this.evaluator = evaluator; 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. * resolved SpEL value.
*/ */
private static class ConverterAwareSpELExpressionParameterValueProvider private static class ConverterAwareExpressionParameterValueProvider
extends SpELExpressionParameterValueProvider<RelationalPersistentProperty> { extends ValueExpressionParameterValueProvider<RelationalPersistentProperty> {
private final ConversionContext context; private final ConversionContext context;
/** /**
* Creates a new {@link ConverterAwareSpELExpressionParameterValueProvider}. * Creates a new {@link ConverterAwareExpressionParameterValueProvider}.
* *
* @param context must not be {@literal null}. * @param context must not be {@literal null}.
* @param evaluator must not be {@literal null}. * @param evaluator must not be {@literal null}.
* @param conversionService must not be {@literal null}. * @param conversionService must not be {@literal null}.
* @param delegate must not be {@literal null}. * @param delegate must not be {@literal null}.
*/ */
public ConverterAwareSpELExpressionParameterValueProvider(ConversionContext context, public ConverterAwareExpressionParameterValueProvider(ConversionContext context, ValueExpressionEvaluator evaluator,
SpELExpressionEvaluator evaluator, ConversionService conversionService, ConversionService conversionService,
ParameterValueProvider<RelationalPersistentProperty> delegate) { ParameterValueProvider<RelationalPersistentProperty> delegate) {
super(evaluator, conversionService, delegate); super(evaluator, conversionService, delegate);
@ -1194,9 +1218,11 @@ public class MappingRelationalConverter extends AbstractRelationalConverter impl
} }
@Override @Override
protected <T> T potentiallyConvertSpelValue(Object object, Parameter<T, RelationalPersistentProperty> parameter) { protected <T> T potentiallyConvertExpressionValue(Object object,
Parameter<T, RelationalPersistentProperty> parameter) {
return context.convert(object, parameter.getType()); return context.convert(object, parameter.getType());
} }
} }
private record PropertyTranslatingPropertyAccessor<T>(PersistentPropertyAccessor<T> delegate, private record PropertyTranslatingPropertyAccessor<T>(PersistentPropertyAccessor<T> delegate,

Loading…
Cancel
Save