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
6573private static final Logger LOG = LoggerFactory .getLogger (BasicJdbcConverter .class );
6674private static final Converter <Iterable <?>, Map <?, ?>> ITERABLE_OF_ENTRY_TO_MAP_CONVERTER = new IterableOfEntryToMapConverter ();
@@ -69,6 +77,7 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
6977private final IdentifierProcessing identifierProcessing ;
7078
7179private 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
8998Assert .notNull (relationResolver , "RelationResolver must not be null" );
9099
91- this .relationResolver = relationResolver ;
92100this .typeFactory = JdbcTypeFactory .unsupported ();
93101this .identifierProcessing = IdentifierProcessing .ANSI ;
102+ this .relationResolver = relationResolver ;
103+ this .spELContext = new SpELContext (ResultSetAccessorPropertyAccessor .INSTANCE );
94104}
95105
96106/**
@@ -113,9 +123,19 @@ public BasicJdbcConverter(
113123Assert .notNull (relationResolver , "RelationResolver must not be null" );
114124Assert .notNull (identifierProcessing , "IdentifierProcessing must not be null" );
115125
116- this .relationResolver = relationResolver ;
117126this .typeFactory = typeFactory ;
118127this .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
345365private final JdbcPropertyValueProvider propertyValueProvider ;
346366private final JdbcBackReferencePropertyValueProvider backReferencePropertyValueProvider ;
367+ private final ResultSetAccessor accessor ;
347368
348369@ SuppressWarnings ("unchecked" )
349370private ReadingContext (PersistentPropertyPathExtension rootPath , ResultSetAccessor accessor , Identifier identifier ,
350371Object key ) {
351-
352372RelationalPersistentEntity <T > entity = (RelationalPersistentEntity <T >) rootPath .getLeafEntity ();
353373
354374Assert .notNull (entity , "The rootPath must point to an entity." );
@@ -361,26 +381,28 @@ private ReadingContext(PersistentPropertyPathExtension rootPath, ResultSetAccess
361381this .propertyValueProvider = new JdbcPropertyValueProvider (identifierProcessing , path , accessor );
362382this .backReferencePropertyValueProvider = new JdbcBackReferencePropertyValueProvider (identifierProcessing , path ,
363383accessor );
384+ this .accessor = accessor ;
364385}
365386
366387private ReadingContext (RelationalPersistentEntity <T > entity , PersistentPropertyPathExtension rootPath ,
367388PersistentPropertyPathExtension path , Identifier identifier , Object key ,
368389JdbcPropertyValueProvider propertyValueProvider ,
369- JdbcBackReferencePropertyValueProvider backReferencePropertyValueProvider ) {
390+ JdbcBackReferencePropertyValueProvider backReferencePropertyValueProvider , ResultSetAccessor accessor ) {
370391this .entity = entity ;
371392this .rootPath = rootPath ;
372393this .path = path ;
373394this .identifier = identifier ;
374395this .key = key ;
375396this .propertyValueProvider = propertyValueProvider ;
376397this .backReferencePropertyValueProvider = backReferencePropertyValueProvider ;
398+ this .accessor = accessor ;
377399}
378400
379401private <S > ReadingContext <S > extendBy (RelationalPersistentProperty property ) {
380402return new ReadingContext <>(
381403(RelationalPersistentEntity <S >) getMappingContext ().getRequiredPersistentEntity (property .getActualType ()),
382404rootPath .extendBy (property ), path .extendBy (property ), identifier , key ,
383- propertyValueProvider .extendBy (property ), backReferencePropertyValueProvider .extendBy (property ));
405+ propertyValueProvider .extendBy (property ), backReferencePropertyValueProvider .extendBy (property ), accessor );
384406}
385407
386408T mapRow () {
@@ -529,23 +551,70 @@ private Object readEntityFrom(RelationalPersistentProperty property) {
529551
530552private 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
542568return 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
547606private boolean isSimpleProperty (RelationalPersistentProperty property ) {
548607return !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