24
24
25
25
import org .slf4j .Logger ;
26
26
import org .slf4j .LoggerFactory ;
27
+
28
+ import org .springframework .context .ApplicationContext ;
29
+ import org .springframework .context .ApplicationContextAware ;
27
30
import org .springframework .core .convert .ConverterNotFoundException ;
28
31
import org .springframework .core .convert .converter .Converter ;
29
32
import org .springframework .data .convert .CustomConversions ;
33
36
import org .springframework .data .mapping .PersistentPropertyPath ;
34
37
import org .springframework .data .mapping .PreferredConstructor ;
35
38
import org .springframework .data .mapping .context .MappingContext ;
39
+ import org .springframework .data .mapping .model .DefaultSpELExpressionEvaluator ;
40
+ import org .springframework .data .mapping .model .ParameterValueProvider ;
36
41
import 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 ;
37
45
import org .springframework .data .relational .core .conversion .BasicRelationalConverter ;
38
46
import org .springframework .data .relational .core .conversion .RelationalConverter ;
39
47
import org .springframework .data .relational .core .mapping .PersistentPropertyPathExtension ;
60
68
* @see CustomConversions
61
69
* @since 1.1
62
70
*/
63
- public class BasicJdbcConverter extends BasicRelationalConverter implements JdbcConverter {
71
+ public class BasicJdbcConverter extends BasicRelationalConverter implements JdbcConverter , ApplicationContextAware {
64
72
65
73
private static final Logger LOG = LoggerFactory .getLogger (BasicJdbcConverter .class );
66
74
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
69
77
private final IdentifierProcessing identifierProcessing ;
70
78
71
79
private final RelationResolver relationResolver ;
80
+ private SpELContext spELContext ;
72
81
73
82
/**
74
83
* Creates a new {@link BasicRelationalConverter} given {@link MappingContext} and a
@@ -88,9 +97,10 @@ public BasicJdbcConverter(
88
97
89
98
Assert .notNull (relationResolver , "RelationResolver must not be null" );
90
99
91
- this .relationResolver = relationResolver ;
92
100
this .typeFactory = JdbcTypeFactory .unsupported ();
93
101
this .identifierProcessing = IdentifierProcessing .ANSI ;
102
+ this .relationResolver = relationResolver ;
103
+ this .spELContext = new SpELContext (ResultSetAccessorPropertyAccessor .INSTANCE );
94
104
}
95
105
96
106
/**
@@ -113,9 +123,19 @@ public BasicJdbcConverter(
113
123
Assert .notNull (relationResolver , "RelationResolver must not be null" );
114
124
Assert .notNull (identifierProcessing , "IdentifierProcessing must not be null" );
115
125
116
- this .relationResolver = relationResolver ;
117
126
this .typeFactory = typeFactory ;
118
127
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 );
119
139
}
120
140
121
141
@ Nullable
@@ -344,11 +364,11 @@ private class ReadingContext<T> {
344
364
345
365
private final JdbcPropertyValueProvider propertyValueProvider ;
346
366
private final JdbcBackReferencePropertyValueProvider backReferencePropertyValueProvider ;
367
+ private final ResultSetAccessor accessor ;
347
368
348
369
@ SuppressWarnings ("unchecked" )
349
370
private ReadingContext (PersistentPropertyPathExtension rootPath , ResultSetAccessor accessor , Identifier identifier ,
350
371
Object key ) {
351
-
352
372
RelationalPersistentEntity <T > entity = (RelationalPersistentEntity <T >) rootPath .getLeafEntity ();
353
373
354
374
Assert .notNull (entity , "The rootPath must point to an entity." );
@@ -361,26 +381,28 @@ private ReadingContext(PersistentPropertyPathExtension rootPath, ResultSetAccess
361
381
this .propertyValueProvider = new JdbcPropertyValueProvider (identifierProcessing , path , accessor );
362
382
this .backReferencePropertyValueProvider = new JdbcBackReferencePropertyValueProvider (identifierProcessing , path ,
363
383
accessor );
384
+ this .accessor = accessor ;
364
385
}
365
386
366
387
private ReadingContext (RelationalPersistentEntity <T > entity , PersistentPropertyPathExtension rootPath ,
367
388
PersistentPropertyPathExtension path , Identifier identifier , Object key ,
368
389
JdbcPropertyValueProvider propertyValueProvider ,
369
- JdbcBackReferencePropertyValueProvider backReferencePropertyValueProvider ) {
390
+ JdbcBackReferencePropertyValueProvider backReferencePropertyValueProvider , ResultSetAccessor accessor ) {
370
391
this .entity = entity ;
371
392
this .rootPath = rootPath ;
372
393
this .path = path ;
373
394
this .identifier = identifier ;
374
395
this .key = key ;
375
396
this .propertyValueProvider = propertyValueProvider ;
376
397
this .backReferencePropertyValueProvider = backReferencePropertyValueProvider ;
398
+ this .accessor = accessor ;
377
399
}
378
400
379
401
private <S > ReadingContext <S > extendBy (RelationalPersistentProperty property ) {
380
402
return new ReadingContext <>(
381
403
(RelationalPersistentEntity <S >) getMappingContext ().getRequiredPersistentEntity (property .getActualType ()),
382
404
rootPath .extendBy (property ), path .extendBy (property ), identifier , key ,
383
- propertyValueProvider .extendBy (property ), backReferencePropertyValueProvider .extendBy (property ));
405
+ propertyValueProvider .extendBy (property ), backReferencePropertyValueProvider .extendBy (property ), accessor );
384
406
}
385
407
386
408
T mapRow () {
@@ -529,23 +551,70 @@ private Object readEntityFrom(RelationalPersistentProperty property) {
529
551
530
552
private T createInstanceInternal (@ Nullable Object idValue ) {
531
553
532
- T instance = createInstance (entity , parameter -> {
554
+ PreferredConstructor <T , RelationalPersistentProperty > persistenceConstructor = entity .getPersistenceConstructor ();
555
+ ParameterValueProvider <RelationalPersistentProperty > provider ;
533
556
534
- String parameterName = parameter . getName ();
557
+ if ( persistenceConstructor != null && persistenceConstructor . hasParameters ()) {
535
558
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
+ }
537
565
538
- RelationalPersistentProperty property = entity .getRequiredPersistentProperty (parameterName );
539
- return readOrLoadProperty (idValue , property );
540
- });
566
+ T instance = createInstance (entity , provider ::getParameterValue );
541
567
542
568
return entity .requiresPropertyPopulation () ? populateProperties (instance , idValue ) : instance ;
543
569
}
544
570
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
+ }
545
604
}
546
605
547
606
private boolean isSimpleProperty (RelationalPersistentProperty property ) {
548
607
return !property .isCollectionLike () && !property .isEntity () && !property .isMap () && !property .isEmbedded ();
549
608
}
550
609
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
+
551
620
}
0 commit comments