2424
2525import org .slf4j .Logger ;
2626import org .slf4j .LoggerFactory ;
27+
28+ import org .springframework .context .ApplicationContext ;
29+ import org .springframework .context .ApplicationContextAware ;
2730import org .springframework .core .convert .ConverterNotFoundException ;
2831import org .springframework .core .convert .converter .Converter ;
2932import org .springframework .data .convert .CustomConversions ;
3336import org .springframework .data .mapping .PersistentPropertyPath ;
3437import org .springframework .data .mapping .PreferredConstructor ;
3538import org .springframework .data .mapping .context .MappingContext ;
39+ import org .springframework .data .mapping .model .DefaultSpELExpressionEvaluator ;
40+ import org .springframework .data .mapping .model .ParameterValueProvider ;
3641import org .springframework .data .mapping .model .SimpleTypeHolder ;
42+ import org .springframework .data .mapping .model .SpELContext ;
43+ import org .springframework .data .mapping .model .SpELExpressionEvaluator ;
44+ import org .springframework .data .mapping .model .SpELExpressionParameterValueProvider ;
3745import org .springframework .data .relational .core .conversion .BasicRelationalConverter ;
3846import org .springframework .data .relational .core .conversion .RelationalConverter ;
3947import org .springframework .data .relational .core .mapping .PersistentPropertyPathExtension ;
6068 * @see CustomConversions
6169 * @since 1.1
6270 */
63- public class BasicJdbcConverter extends BasicRelationalConverter implements JdbcConverter {
71+ public class BasicJdbcConverter extends BasicRelationalConverter implements JdbcConverter , ApplicationContextAware {
6472
6573 private static final Logger LOG = LoggerFactory .getLogger (BasicJdbcConverter .class );
6674 private static final Converter <Iterable <?>, Map <?, ?>> ITERABLE_OF_ENTRY_TO_MAP_CONVERTER = new IterableOfEntryToMapConverter ();
@@ -69,6 +77,7 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
6977 private final IdentifierProcessing identifierProcessing ;
7078
7179 private final RelationResolver relationResolver ;
80+ private SpELContext spELContext ;
7281
7382 /**
7483 * Creates a new {@link BasicRelationalConverter} given {@link MappingContext} and a
@@ -88,9 +97,10 @@ public BasicJdbcConverter(
8897
8998 Assert .notNull (relationResolver , "RelationResolver must not be null" );
9099
91- this .relationResolver = relationResolver ;
92100 this .typeFactory = JdbcTypeFactory .unsupported ();
93101 this .identifierProcessing = IdentifierProcessing .ANSI ;
102+ this .relationResolver = relationResolver ;
103+ this .spELContext = new SpELContext (ResultSetAccessorPropertyAccessor .INSTANCE );
94104 }
95105
96106 /**
@@ -113,9 +123,19 @@ public BasicJdbcConverter(
113123 Assert .notNull (relationResolver , "RelationResolver must not be null" );
114124 Assert .notNull (identifierProcessing , "IdentifierProcessing must not be null" );
115125
116- this .relationResolver = relationResolver ;
117126 this .typeFactory = typeFactory ;
118127 this .identifierProcessing = identifierProcessing ;
128+ this .relationResolver = relationResolver ;
129+ this .spELContext = new SpELContext (ResultSetAccessorPropertyAccessor .INSTANCE );
130+ }
131+
132+ /*
133+ * (non-Javadoc)
134+ * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
135+ */
136+ @ Override
137+ public void setApplicationContext (ApplicationContext applicationContext ) {
138+ this .spELContext = new SpELContext (this .spELContext , applicationContext );
119139 }
120140
121141 @ Nullable
@@ -344,11 +364,11 @@ private class ReadingContext<T> {
344364
345365 private final JdbcPropertyValueProvider propertyValueProvider ;
346366 private final JdbcBackReferencePropertyValueProvider backReferencePropertyValueProvider ;
367+ private final ResultSetAccessor accessor ;
347368
348369 @ SuppressWarnings ("unchecked" )
349370 private ReadingContext (PersistentPropertyPathExtension rootPath , ResultSetAccessor accessor , Identifier identifier ,
350371 Object key ) {
351-
352372 RelationalPersistentEntity <T > entity = (RelationalPersistentEntity <T >) rootPath .getLeafEntity ();
353373
354374 Assert .notNull (entity , "The rootPath must point to an entity." );
@@ -361,26 +381,28 @@ private ReadingContext(PersistentPropertyPathExtension rootPath, ResultSetAccess
361381 this .propertyValueProvider = new JdbcPropertyValueProvider (identifierProcessing , path , accessor );
362382 this .backReferencePropertyValueProvider = new JdbcBackReferencePropertyValueProvider (identifierProcessing , path ,
363383 accessor );
384+ this .accessor = accessor ;
364385 }
365386
366387 private ReadingContext (RelationalPersistentEntity <T > entity , PersistentPropertyPathExtension rootPath ,
367388 PersistentPropertyPathExtension path , Identifier identifier , Object key ,
368389 JdbcPropertyValueProvider propertyValueProvider ,
369- JdbcBackReferencePropertyValueProvider backReferencePropertyValueProvider ) {
390+ JdbcBackReferencePropertyValueProvider backReferencePropertyValueProvider , ResultSetAccessor accessor ) {
370391 this .entity = entity ;
371392 this .rootPath = rootPath ;
372393 this .path = path ;
373394 this .identifier = identifier ;
374395 this .key = key ;
375396 this .propertyValueProvider = propertyValueProvider ;
376397 this .backReferencePropertyValueProvider = backReferencePropertyValueProvider ;
398+ this .accessor = accessor ;
377399 }
378400
379401 private <S > ReadingContext <S > extendBy (RelationalPersistentProperty property ) {
380402 return new ReadingContext <>(
381403 (RelationalPersistentEntity <S >) getMappingContext ().getRequiredPersistentEntity (property .getActualType ()),
382404 rootPath .extendBy (property ), path .extendBy (property ), identifier , key ,
383- propertyValueProvider .extendBy (property ), backReferencePropertyValueProvider .extendBy (property ));
405+ propertyValueProvider .extendBy (property ), backReferencePropertyValueProvider .extendBy (property ), accessor );
384406 }
385407
386408 T mapRow () {
@@ -529,23 +551,70 @@ private Object readEntityFrom(RelationalPersistentProperty property) {
529551
530552 private T createInstanceInternal (@ Nullable Object idValue ) {
531553
532- T instance = createInstance (entity , parameter -> {
554+ PreferredConstructor <T , RelationalPersistentProperty > persistenceConstructor = entity .getPersistenceConstructor ();
555+ ParameterValueProvider <RelationalPersistentProperty > provider ;
533556
534- String parameterName = parameter . getName ();
557+ if ( persistenceConstructor != null && persistenceConstructor . hasParameters ()) {
535558
536- Assert .notNull (parameterName , "A constructor parameter name must not be null to be used with Spring Data JDBC" );
559+ SpELExpressionEvaluator expressionEvaluator = new DefaultSpELExpressionEvaluator (accessor , spELContext );
560+ provider = new SpELExpressionParameterValueProvider <>(expressionEvaluator , getConversionService (),
561+ new ResultSetParameterValueProvider (idValue , entity ));
562+ } else {
563+ provider = NoOpParameterValueProvider .INSTANCE ;
564+ }
537565
538- RelationalPersistentProperty property = entity .getRequiredPersistentProperty (parameterName );
539- return readOrLoadProperty (idValue , property );
540- });
566+ T instance = createInstance (entity , provider ::getParameterValue );
541567
542568 return entity .requiresPropertyPopulation () ? populateProperties (instance , idValue ) : instance ;
543569 }
544570
571+ /**
572+ * {@link ParameterValueProvider} that reads a simple property or materializes an object for a
573+ * {@link RelationalPersistentProperty}.
574+ *
575+ * @see #readOrLoadProperty(Object, RelationalPersistentProperty)
576+ * @since 2.1
577+ */
578+ private class ResultSetParameterValueProvider implements ParameterValueProvider <RelationalPersistentProperty > {
579+
580+ private final @ Nullable Object idValue ;
581+ private final RelationalPersistentEntity <?> entity ;
582+
583+ public ResultSetParameterValueProvider (@ Nullable Object idValue , RelationalPersistentEntity <?> entity ) {
584+ this .idValue = idValue ;
585+ this .entity = entity ;
586+ }
587+
588+ /*
589+ * (non-Javadoc)
590+ * @see org.springframework.data.mapping.model.ParameterValueProvider#getParameterValue(org.springframework.data.mapping.PreferredConstructor.Parameter)
591+ */
592+ @ Override
593+ @ Nullable
594+ public <T > T getParameterValue (PreferredConstructor .Parameter <T , RelationalPersistentProperty > parameter ) {
595+
596+ String parameterName = parameter .getName ();
597+
598+ Assert .notNull (parameterName , "A constructor parameter name must not be null to be used with Spring Data JDBC" );
599+
600+ RelationalPersistentProperty property = entity .getRequiredPersistentProperty (parameterName );
601+ return (T ) readOrLoadProperty (idValue , property );
602+ }
603+ }
545604 }
546605
547606 private boolean isSimpleProperty (RelationalPersistentProperty property ) {
548607 return !property .isCollectionLike () && !property .isEntity () && !property .isMap () && !property .isEmbedded ();
549608 }
550609
610+ enum NoOpParameterValueProvider implements ParameterValueProvider <RelationalPersistentProperty > {
611+
612+ INSTANCE ;
613+
614+ @ Override
615+ public <T > T getParameterValue (PreferredConstructor .Parameter <T , RelationalPersistentProperty > parameter ) {
616+ return null ;
617+ }
618+ }
619+
551620}
0 commit comments