49
49
import org .springframework .dao .InvalidDataAccessApiUsageException ;
50
50
import org .springframework .data .domain .Pageable ;
51
51
import org .springframework .data .domain .Sort ;
52
+ import org .springframework .data .projection .ProjectionFactory ;
52
53
import org .springframework .data .r2dbc .UncategorizedR2dbcException ;
53
54
import org .springframework .data .r2dbc .connectionfactory .ConnectionFactoryUtils ;
54
55
import org .springframework .data .r2dbc .connectionfactory .ConnectionProxy ;
@@ -82,13 +83,17 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
82
83
83
84
private final DefaultDatabaseClientBuilder builder ;
84
85
86
+ private final ProjectionFactory projectionFactory ;
87
+
85
88
DefaultDatabaseClient (ConnectionFactory connector , R2dbcExceptionTranslator exceptionTranslator ,
86
- ReactiveDataAccessStrategy dataAccessStrategy , boolean namedParameters , DefaultDatabaseClientBuilder builder ) {
89
+ ReactiveDataAccessStrategy dataAccessStrategy , boolean namedParameters , ProjectionFactory projectionFactory ,
90
+ DefaultDatabaseClientBuilder builder ) {
87
91
88
92
this .connector = connector ;
89
93
this .exceptionTranslator = exceptionTranslator ;
90
94
this .dataAccessStrategy = dataAccessStrategy ;
91
95
this .namedParameters = namedParameters ;
96
+ this .projectionFactory = projectionFactory ;
92
97
this .builder = builder ;
93
98
}
94
99
@@ -544,7 +549,7 @@ protected ExecuteSpecSupport createInstance(Map<Integer, SettableValue> byIndex,
544
549
@ SuppressWarnings ("unchecked" )
545
550
protected class DefaultTypedExecuteSpec <T > extends ExecuteSpecSupport implements TypedExecuteSpec <T > {
546
551
547
- private final Class <T > typeToRead ;
552
+ private final @ Nullable Class <T > typeToRead ;
548
553
private final BiFunction <Row , RowMetadata , T > mappingFunction ;
549
554
550
555
DefaultTypedExecuteSpec (Map <Integer , SettableValue > byIndex , Map <String , SettableValue > byName ,
@@ -553,7 +558,13 @@ protected class DefaultTypedExecuteSpec<T> extends ExecuteSpecSupport implements
553
558
super (byIndex , byName , sqlSupplier );
554
559
555
560
this .typeToRead = typeToRead ;
556
- this .mappingFunction = dataAccessStrategy .getRowMapper (typeToRead );
561
+
562
+ if (typeToRead .isInterface ()) {
563
+ this .mappingFunction = ColumnMapRowMapper .INSTANCE
564
+ .andThen (map -> projectionFactory .createProjection (typeToRead , map ));
565
+ } else {
566
+ this .mappingFunction = dataAccessStrategy .getRowMapper (typeToRead );
567
+ }
557
568
}
558
569
559
570
DefaultTypedExecuteSpec (Map <Integer , SettableValue > byIndex , Map <String , SettableValue > byName ,
@@ -638,6 +649,9 @@ public GenericSelectSpec from(String table) {
638
649
639
650
@ Override
640
651
public <T > TypedSelectSpec <T > from (Class <T > table ) {
652
+
653
+ assertRegularClass (table );
654
+
641
655
return new DefaultTypedSelectSpec <>(table );
642
656
}
643
657
}
@@ -735,8 +749,16 @@ public <R> TypedSelectSpec<R> as(Class<R> resultType) {
735
749
736
750
Assert .notNull (resultType , "Result type must not be null!" );
737
751
752
+ BiFunction <Row , RowMetadata , R > rowMapper ;
753
+
754
+ if (resultType .isInterface ()) {
755
+ rowMapper = ColumnMapRowMapper .INSTANCE .andThen (map -> projectionFactory .createProjection (resultType , map ));
756
+ } else {
757
+ rowMapper = dataAccessStrategy .getRowMapper (resultType );
758
+ }
759
+
738
760
return new DefaultTypedSelectSpec <>(this .table , this .projectedFields , this .criteria , this .sort , this .page ,
739
- resultType , dataAccessStrategy . getRowMapper ( resultType ) );
761
+ resultType , rowMapper );
740
762
}
741
763
742
764
@ Override
@@ -808,10 +830,10 @@ protected DefaultGenericSelectSpec createInstance(String table, List<String> pro
808
830
@ SuppressWarnings ("unchecked" )
809
831
private class DefaultTypedSelectSpec <T > extends DefaultSelectSpecSupport implements TypedSelectSpec <T > {
810
832
811
- private final @ Nullable Class <T > typeToRead ;
833
+ private final Class <T > typeToRead ;
812
834
private final BiFunction <Row , RowMetadata , T > mappingFunction ;
813
835
814
- DefaultTypedSelectSpec (@ Nullable Class <T > typeToRead ) {
836
+ DefaultTypedSelectSpec (Class <T > typeToRead ) {
815
837
816
838
super (dataAccessStrategy .getTableName (typeToRead ));
817
839
@@ -833,7 +855,16 @@ public <R> FetchSpec<R> as(Class<R> resultType) {
833
855
834
856
Assert .notNull (resultType , "Result type must not be null!" );
835
857
836
- return exchange (dataAccessStrategy .getRowMapper (resultType ));
858
+ BiFunction <Row , RowMetadata , R > rowMapper ;
859
+
860
+ if (resultType .isInterface ()) {
861
+ rowMapper = dataAccessStrategy .getRowMapper (typeToRead )
862
+ .andThen (r -> projectionFactory .createProjection (resultType , r ));
863
+ } else {
864
+ rowMapper = dataAccessStrategy .getRowMapper (resultType );
865
+ }
866
+
867
+ return exchange (rowMapper );
837
868
}
838
869
839
870
@ Override
@@ -920,6 +951,9 @@ public GenericInsertSpec<Map<String, Object>> into(String table) {
920
951
921
952
@ Override
922
953
public <T > TypedInsertSpec <T > into (Class <T > table ) {
954
+
955
+ assertRegularClass (table );
956
+
923
957
return new DefaultTypedInsertSpec <>(table , ColumnMapRowMapper .INSTANCE );
924
958
}
925
959
}
@@ -1136,6 +1170,9 @@ public GenericUpdateSpec table(String table) {
1136
1170
1137
1171
@ Override
1138
1172
public <T > TypedUpdateSpec <T > table (Class <T > table ) {
1173
+
1174
+ assertRegularClass (table );
1175
+
1139
1176
return new DefaultTypedUpdateSpec <>(table , null , null );
1140
1177
}
1141
1178
}
@@ -1297,6 +1334,9 @@ public DefaultDeleteSpec<?> from(String table) {
1297
1334
1298
1335
@ Override
1299
1336
public <T > DefaultDeleteSpec <T > from (Class <T > table ) {
1337
+
1338
+ assertRegularClass (table );
1339
+
1300
1340
return new DefaultDeleteSpec <>(table , null , null );
1301
1341
}
1302
1342
}
@@ -1477,6 +1517,13 @@ private static String getRequiredSql(Supplier<String> sqlSupplier) {
1477
1517
return sql ;
1478
1518
}
1479
1519
1520
+ private static void assertRegularClass (Class <?> table ) {
1521
+
1522
+ Assert .notNull (table , "Entity type must not be null" );
1523
+ Assert .isTrue (!table .isInterface () && !table .isEnum (),
1524
+ () -> String .format ("Entity type %s must be a class" , table .getName ()));
1525
+ }
1526
+
1480
1527
/**
1481
1528
* Invocation handler that suppresses close calls on R2DBC Connections. Also prepares returned Statement
1482
1529
* (Prepared/CallbackStatement) objects.
0 commit comments