Skip to content

Commit 5279c5f

Browse files
committed
Add support for ValueExpression.
Closes #1477
1 parent d01caa4 commit 5279c5f

File tree

10 files changed

+138
-70
lines changed

10 files changed

+138
-70
lines changed

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/MappingCassandraConverter.java

+58-25
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,13 @@
3232
import org.springframework.beans.factory.BeanClassLoaderAware;
3333
import org.springframework.context.ApplicationContext;
3434
import org.springframework.context.ApplicationContextAware;
35+
import org.springframework.context.EnvironmentAware;
3536
import org.springframework.core.CollectionFactory;
3637
import org.springframework.core.convert.ConversionService;
3738
import org.springframework.core.convert.support.DefaultConversionService;
39+
import org.springframework.core.env.Environment;
40+
import org.springframework.core.env.EnvironmentCapable;
41+
import org.springframework.core.env.StandardEnvironment;
3842
import org.springframework.dao.InvalidDataAccessApiUsageException;
3943
import org.springframework.data.cassandra.core.mapping.*;
4044
import org.springframework.data.cassandra.core.mapping.Embedded.OnEmpty;
@@ -46,19 +50,20 @@
4650
import org.springframework.data.mapping.PersistentProperty;
4751
import org.springframework.data.mapping.PersistentPropertyAccessor;
4852
import org.springframework.data.mapping.context.MappingContext;
53+
import org.springframework.data.mapping.model.CachingValueExpressionEvaluatorFactory;
4954
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
50-
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
5155
import org.springframework.data.mapping.model.EntityInstantiator;
5256
import org.springframework.data.mapping.model.ParameterValueProvider;
5357
import org.springframework.data.mapping.model.PropertyValueProvider;
5458
import org.springframework.data.mapping.model.SpELContext;
55-
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
56-
import org.springframework.data.mapping.model.SpELExpressionParameterValueProvider;
59+
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
60+
import org.springframework.data.mapping.model.ValueExpressionParameterValueProvider;
5761
import org.springframework.data.projection.EntityProjection;
5862
import org.springframework.data.projection.ProjectionFactory;
5963
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
6064
import org.springframework.data.util.Predicates;
6165
import org.springframework.data.util.TypeInformation;
66+
import org.springframework.expression.spel.standard.SpelExpressionParser;
6267
import org.springframework.lang.Nullable;
6368
import org.springframework.util.Assert;
6469
import org.springframework.util.ClassUtils;
@@ -87,7 +92,7 @@
8792
* @author Frank Spitulski
8893
*/
8994
public class MappingCassandraConverter extends AbstractCassandraConverter
90-
implements ApplicationContextAware, BeanClassLoaderAware {
95+
implements ApplicationContextAware, EnvironmentAware, EnvironmentCapable, BeanClassLoaderAware {
9196

9297
private final Log log = LogFactory.getLog(getClass());
9398

@@ -99,11 +104,21 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
99104

100105
private @Nullable ClassLoader beanClassLoader;
101106

107+
private @Nullable Environment environment;
108+
102109
private SpELContext spELContext;
103110

104111
private final DefaultColumnTypeResolver cassandraTypeResolver;
112+
105113
private final EmbeddedEntityOperations embeddedEntityOperations;
106-
private final SpelAwareProxyProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory();
114+
115+
private final SpelExpressionParser expressionParser = new SpelExpressionParser();
116+
117+
private final SpelAwareProxyProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory(
118+
expressionParser);
119+
120+
private final CachingValueExpressionEvaluatorFactory expressionEvaluatorFactory = new CachingValueExpressionEvaluatorFactory(
121+
expressionParser, this, o -> spELContext.getEvaluationContext(o));
107122

108123
/**
109124
* Create a new {@link MappingCassandraConverter} with a {@link CassandraMappingContext}.
@@ -171,10 +186,30 @@ private static CassandraMappingContext newDefaultMappingContext(CassandraCustomC
171186

172187
@Override
173188
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
189+
174190
this.spELContext = new SpELContext(this.spELContext, applicationContext);
191+
this.environment = applicationContext.getEnvironment();
175192
this.projectionFactory.setBeanFactory(applicationContext);
176193
}
177194

195+
@Override
196+
public void setEnvironment(Environment environment) {
197+
this.environment = environment;
198+
}
199+
200+
@Override
201+
public Environment getEnvironment() {
202+
203+
if (this.environment == null) {
204+
this.environment = new StandardEnvironment();
205+
}
206+
return this.environment;
207+
}
208+
209+
public void setSpELContext(SpELContext spELContext) {
210+
this.spELContext = spELContext;
211+
}
212+
178213
@Override
179214
public void setBeanClassLoader(ClassLoader classLoader) {
180215
this.beanClassLoader = classLoader;
@@ -294,8 +329,7 @@ public <R> R project(EntityProjection<R, ?> projection, Row row) {
294329
this::doReadTupleValue, this::doReadUdtValue, this::readCollectionOrArray, this::readMap,
295330
this::getPotentiallyConvertedSimpleRead, projection);
296331

297-
return doReadProjection(context, new RowValueProvider(row, new DefaultSpELExpressionEvaluator(row, spELContext)),
298-
projection);
332+
return doReadProjection(context, new RowValueProvider(row, expressionEvaluatorFactory.create(row)), projection);
299333
}
300334

301335
@SuppressWarnings("unchecked")
@@ -334,11 +368,10 @@ private <R> R doReadProjection(ConversionContext context, CassandraValueProvider
334368

335369
ParameterValueProvider<CassandraPersistentProperty> provider;
336370
if (persistenceCreator != null && persistenceCreator.hasParameters()) {
337-
SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(valueProviderToUse.getSource(),
338-
spELContext);
371+
ValueExpressionEvaluator evaluator = expressionEvaluatorFactory.create(valueProviderToUse.getSource());
339372
ParameterValueProvider<CassandraPersistentProperty> parameterValueProvider = newParameterValueProvider(context,
340373
entity, valueProviderToUse);
341-
provider = new ConverterAwareSpELExpressionParameterValueProvider(evaluator, getConversionService(),
374+
provider = new ConverterAwareValueExpressionParameterValueProvider(evaluator, getConversionService(),
342375
parameterValueProvider, context);
343376
} else {
344377
provider = NoOpParameterValueProvider.INSTANCE;
@@ -362,8 +395,7 @@ private Object doReadOrProject(ConversionContext context, Row row, TypeInformati
362395

363396
if (typeDescriptor.isProjection()) {
364397

365-
CassandraValueProvider valueProvider = new RowValueProvider(row,
366-
new DefaultSpELExpressionEvaluator(row, this.spELContext));
398+
CassandraValueProvider valueProvider = new RowValueProvider(row, expressionEvaluatorFactory.create(row));
367399
return doReadProjection(context, valueProvider, typeDescriptor);
368400
}
369401

@@ -376,7 +408,7 @@ private Object doReadOrProject(ConversionContext context, UdtValue udtValue, Typ
376408
if (typeDescriptor.isProjection()) {
377409

378410
CassandraValueProvider valueProvider = new UdtValueProvider(udtValue,
379-
new DefaultSpELExpressionEvaluator(udtValue, this.spELContext));
411+
expressionEvaluatorFactory.create(udtValue));
380412
return doReadProjection(context, valueProvider, typeDescriptor);
381413
}
382414

@@ -389,7 +421,7 @@ private Object doReadOrProject(ConversionContext context, TupleValue tupleValue,
389421
if (typeDescriptor.isProjection()) {
390422

391423
CassandraValueProvider valueProvider = new TupleValueProvider(tupleValue,
392-
new DefaultSpELExpressionEvaluator(tupleValue, this.spELContext));
424+
expressionEvaluatorFactory.create(tupleValue));
393425
return doReadProjection(context, valueProvider, typeDescriptor);
394426
}
395427

@@ -436,10 +468,10 @@ <S> S doReadUdtValue(ConversionContext context, UdtValue udtValue, TypeInformati
436468
}
437469

438470
private <S> S doReadEntity(ConversionContext context, Object value,
439-
Function<SpELExpressionEvaluator, CassandraValueProvider> valueProviderSupplier,
471+
Function<ValueExpressionEvaluator, CassandraValueProvider> valueProviderSupplier,
440472
TypeInformation<? extends S> typeHint) {
441473

442-
SpELExpressionEvaluator expressionEvaluator = new DefaultSpELExpressionEvaluator(value, this.spELContext);
474+
ValueExpressionEvaluator expressionEvaluator = expressionEvaluatorFactory.create(value);
443475
CassandraValueProvider valueProvider = valueProviderSupplier.apply(expressionEvaluator);
444476

445477
return doReadEntity(context, valueProvider, typeHint);
@@ -507,10 +539,10 @@ private <S> S doReadEntity(ConversionContext context, CassandraValueProvider val
507539
ParameterValueProvider<CassandraPersistentProperty> provider;
508540

509541
if (persistenceCreator != null && persistenceCreator.hasParameters()) {
510-
SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(valueProvider.getSource(), spELContext);
542+
ValueExpressionEvaluator evaluator = expressionEvaluatorFactory.create(valueProvider.getSource());
511543
ParameterValueProvider<CassandraPersistentProperty> parameterValueProvider = newParameterValueProvider(context,
512544
entity, valueProvider);
513-
provider = new ConverterAwareSpELExpressionParameterValueProvider(evaluator, getConversionService(),
545+
provider = new ConverterAwareValueExpressionParameterValueProvider(evaluator, getConversionService(),
514546
parameterValueProvider, context);
515547
} else {
516548
provider = NoOpParameterValueProvider.INSTANCE;
@@ -1261,23 +1293,23 @@ public <T> T getParameterValue(Parameter<T, CassandraPersistentProperty> paramet
12611293
}
12621294

12631295
/**
1264-
* Extension of {@link SpELExpressionParameterValueProvider} to recursively trigger value conversion on the raw
1296+
* Extension of {@link ValueExpressionParameterValueProvider} to recursively trigger value conversion on the raw
12651297
* resolved SpEL value.
12661298
*/
1267-
private static class ConverterAwareSpELExpressionParameterValueProvider
1268-
extends SpELExpressionParameterValueProvider<CassandraPersistentProperty> {
1299+
private static class ConverterAwareValueExpressionParameterValueProvider
1300+
extends ValueExpressionParameterValueProvider<CassandraPersistentProperty> {
12691301

12701302
private final ConversionContext context;
12711303

12721304
/**
1273-
* Creates a new {@link ConverterAwareSpELExpressionParameterValueProvider}.
1305+
* Creates a new {@link ConverterAwareValueExpressionParameterValueProvider}.
12741306
*
12751307
* @param evaluator must not be {@literal null}.
12761308
* @param conversionService must not be {@literal null}.
12771309
* @param delegate must not be {@literal null}.
12781310
* @param context must not be {@literal null}.
12791311
*/
1280-
public ConverterAwareSpELExpressionParameterValueProvider(SpELExpressionEvaluator evaluator,
1312+
public ConverterAwareValueExpressionParameterValueProvider(ValueExpressionEvaluator evaluator,
12811313
ConversionService conversionService, ParameterValueProvider<CassandraPersistentProperty> delegate,
12821314
ConversionContext context) {
12831315

@@ -1286,8 +1318,9 @@ public ConverterAwareSpELExpressionParameterValueProvider(SpELExpressionEvaluato
12861318
}
12871319

12881320
@Override
1289-
protected <T> T potentiallyConvertSpelValue(Object object, Parameter<T, CassandraPersistentProperty> parameter) {
1290-
return (T) context.convert(object, parameter.getType());
1321+
protected <T> T potentiallyConvertExpressionValue(Object object,
1322+
Parameter<T, CassandraPersistentProperty> parameter) {
1323+
return context.convert(object, parameter.getType());
12911324
}
12921325
}
12931326

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/RowValueProvider.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
package org.springframework.data.cassandra.core.convert;
1717

1818
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
19-
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
19+
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
2020
import org.springframework.lang.Nullable;
2121
import org.springframework.util.Assert;
2222

@@ -33,16 +33,16 @@ public class RowValueProvider implements CassandraValueProvider {
3333

3434
private final RowReader reader;
3535

36-
private final SpELExpressionEvaluator evaluator;
36+
private final ValueExpressionEvaluator evaluator;
3737

3838
/**
3939
* Create a new {@link RowValueProvider} with the given {@link Row}, {@link CodecRegistry} and
40-
* {@link SpELExpressionEvaluator}.
40+
* {@link ValueExpressionEvaluator}.
4141
*
4242
* @param source must not be {@literal null}.
4343
* @param evaluator must not be {@literal null}.
4444
*/
45-
public RowValueProvider(Row source, SpELExpressionEvaluator evaluator) {
45+
public RowValueProvider(Row source, ValueExpressionEvaluator evaluator) {
4646

4747
Assert.notNull(source, "Source Row must not be null");
4848
Assert.notNull(evaluator, "SpELExpressionEvaluator must not be null");

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/TupleValueProvider.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
package org.springframework.data.cassandra.core.convert;
1717

1818
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
19-
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
19+
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
2020
import org.springframework.lang.Nullable;
2121
import org.springframework.util.Assert;
2222

@@ -34,17 +34,17 @@ public class TupleValueProvider implements CassandraValueProvider {
3434

3535
private final CodecRegistry codecRegistry;
3636

37-
private final SpELExpressionEvaluator evaluator;
37+
private final ValueExpressionEvaluator evaluator;
3838

3939
private final TupleValue tupleValue;
4040

4141
/**
42-
* Create a new {@link TupleValueProvider} with the given {@link TupleValue} and {@link SpELExpressionEvaluator}.
42+
* Create a new {@link TupleValueProvider} with the given {@link TupleValue} and {@link ValueExpressionEvaluator}.
4343
*
4444
* @param tupleValue must not be {@literal null}.
4545
* @param evaluator must not be {@literal null}.
4646
*/
47-
public TupleValueProvider(TupleValue tupleValue, SpELExpressionEvaluator evaluator) {
47+
public TupleValueProvider(TupleValue tupleValue, ValueExpressionEvaluator evaluator) {
4848

4949
Assert.notNull(tupleValue, "TupleValue must not be null");
5050
Assert.notNull(evaluator, "SpELExpressionEvaluator must not be null");

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/convert/UdtValueProvider.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
package org.springframework.data.cassandra.core.convert;
1717

1818
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
19-
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
19+
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
2020
import org.springframework.lang.Nullable;
2121
import org.springframework.util.Assert;
2222

@@ -32,15 +32,15 @@ public class UdtValueProvider implements CassandraValueProvider {
3232

3333
private final UdtValue udtValue;
3434

35-
private final SpELExpressionEvaluator evaluator;
35+
private final ValueExpressionEvaluator evaluator;
3636

3737
/**
38-
* Create a new {@link UdtValueProvider} with the given {@link UdtValue} and {@link SpELExpressionEvaluator}.
38+
* Create a new {@link UdtValueProvider} with the given {@link UdtValue} and {@link ValueExpressionEvaluator}.
3939
*
4040
* @param udtValue must not be {@literal null}.
4141
* @param evaluator must not be {@literal null}.
4242
*/
43-
public UdtValueProvider(UdtValue udtValue, SpELExpressionEvaluator evaluator) {
43+
public UdtValueProvider(UdtValue udtValue, ValueExpressionEvaluator evaluator) {
4444

4545
Assert.notNull(udtValue, "UDTValue must not be null");
4646
Assert.notNull(evaluator, "SpELExpressionEvaluator must not be null");

0 commit comments

Comments
 (0)