49
49
import org .springframework .data .geo .Metric ;
50
50
import org .springframework .data .mapping .MappingException ;
51
51
import org .springframework .data .mapping .callback .EntityCallbacks ;
52
+ import org .springframework .data .mapping .context .EntityProjection ;
52
53
import org .springframework .data .mapping .context .MappingContext ;
53
54
import org .springframework .data .mongodb .MongoDatabaseFactory ;
54
55
import org .springframework .data .mongodb .MongoDatabaseUtils ;
102
103
import org .springframework .data .mongodb .core .timeseries .Granularity ;
103
104
import org .springframework .data .mongodb .core .validation .Validator ;
104
105
import org .springframework .data .mongodb .util .BsonUtils ;
105
- import org .springframework .data .projection .SpelAwareProxyProjectionFactory ;
106
106
import org .springframework .data .util .CloseableIterator ;
107
107
import org .springframework .data .util .Optionals ;
108
108
import org .springframework .lang .Nullable ;
@@ -173,7 +173,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
173
173
private final QueryMapper queryMapper ;
174
174
private final UpdateMapper updateMapper ;
175
175
private final JsonSchemaMapper schemaMapper ;
176
- private final SpelAwareProxyProjectionFactory projectionFactory ;
177
176
private final EntityOperations operations ;
178
177
private final PropertyOperations propertyOperations ;
179
178
private final QueryOperations queryOperations ;
@@ -225,8 +224,7 @@ public MongoTemplate(MongoDatabaseFactory mongoDbFactory, @Nullable MongoConvert
225
224
this .queryMapper = new QueryMapper (this .mongoConverter );
226
225
this .updateMapper = new UpdateMapper (this .mongoConverter );
227
226
this .schemaMapper = new MongoJsonSchemaMapper (this .mongoConverter );
228
- this .projectionFactory = new SpelAwareProxyProjectionFactory ();
229
- this .operations = new EntityOperations (this .mongoConverter .getMappingContext ());
227
+ this .operations = new EntityOperations (this .mongoConverter );
230
228
this .propertyOperations = new PropertyOperations (this .mongoConverter .getMappingContext ());
231
229
this .queryOperations = new QueryOperations (queryMapper , updateMapper , operations , propertyOperations ,
232
230
mongoDbFactory );
@@ -264,7 +262,6 @@ private MongoTemplate(MongoDatabaseFactory dbFactory, MongoTemplate that) {
264
262
this .queryMapper = that .queryMapper ;
265
263
this .updateMapper = that .updateMapper ;
266
264
this .schemaMapper = that .schemaMapper ;
267
- this .projectionFactory = that .projectionFactory ;
268
265
this .mappingContext = that .mappingContext ;
269
266
this .operations = that .operations ;
270
267
this .propertyOperations = that .propertyOperations ;
@@ -330,9 +327,6 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
330
327
}
331
328
332
329
resourceLoader = applicationContext ;
333
-
334
- projectionFactory .setBeanFactory (applicationContext );
335
- projectionFactory .setBeanClassLoader (applicationContext .getClassLoader ());
336
330
}
337
331
338
332
/**
@@ -416,15 +410,17 @@ protected <T> CloseableIterator<T> doStream(Query query, Class<?> entityType, St
416
410
MongoPersistentEntity <?> persistentEntity = mappingContext .getPersistentEntity (entityType );
417
411
418
412
QueryContext queryContext = queryOperations .createQueryContext (query );
413
+ EntityProjection <T , ?> projection = operations .introspectProjection (returnType ,
414
+ entityType );
419
415
420
416
Document mappedQuery = queryContext .getMappedQuery (persistentEntity );
421
- Document mappedFields = queryContext .getMappedFields (persistentEntity , returnType , projectionFactory );
417
+ Document mappedFields = queryContext .getMappedFields (persistentEntity , projection );
422
418
423
419
FindIterable <Document > cursor = new QueryCursorPreparer (query , entityType ).initiateFind (collection ,
424
420
col -> col .find (mappedQuery , Document .class ).projection (mappedFields ));
425
421
426
422
return new CloseableIterableCursorAdapter <>(cursor , exceptionTranslator ,
427
- new ProjectingReadCallback <>(mongoConverter , entityType , returnType , collectionName ));
423
+ new ProjectingReadCallback <>(mongoConverter , projection , collectionName ));
428
424
});
429
425
}
430
426
@@ -964,9 +960,11 @@ public <T> GeoResults<T> geoNear(NearQuery near, Class<?> domainType, String col
964
960
.withOptions (AggregationOptions .builder ().collation (near .getCollation ()).build ());
965
961
966
962
AggregationResults <Document > results = aggregate ($geoNear , collection , Document .class );
963
+ EntityProjection <T , ?> projection = operations .introspectProjection (returnType ,
964
+ domainType );
967
965
968
966
DocumentCallback <GeoResult <T >> callback = new GeoNearResultDocumentCallback <>(distanceField ,
969
- new ProjectingReadCallback <>(mongoConverter , domainType , returnType , collection ), near .getMetric ());
967
+ new ProjectingReadCallback <>(mongoConverter , projection , collection ), near .getMetric ());
970
968
971
969
List <GeoResult <T >> result = new ArrayList <>();
972
970
@@ -1050,8 +1048,10 @@ public <S, T> T findAndReplace(Query query, S replacement, FindAndReplaceOptions
1050
1048
MongoPersistentEntity <?> entity = mappingContext .getPersistentEntity (entityType );
1051
1049
QueryContext queryContext = queryOperations .createQueryContext (query );
1052
1050
1051
+ EntityProjection <T , S > projection = operations .introspectProjection (resultType ,
1052
+ entityType );
1053
1053
Document mappedQuery = queryContext .getMappedQuery (entity );
1054
- Document mappedFields = queryContext .getMappedFields (entity , resultType , projectionFactory );
1054
+ Document mappedFields = queryContext .getMappedFields (entity , projection );
1055
1055
Document mappedSort = queryContext .getMappedSort (entity );
1056
1056
1057
1057
replacement = maybeCallBeforeConvert (replacement , collectionName );
@@ -1061,7 +1061,8 @@ public <S, T> T findAndReplace(Query query, S replacement, FindAndReplaceOptions
1061
1061
maybeCallBeforeSave (replacement , mappedReplacement , collectionName );
1062
1062
1063
1063
T saved = doFindAndReplace (collectionName , mappedQuery , mappedFields , mappedSort ,
1064
- queryContext .getCollation (entityType ).orElse (null ), entityType , mappedReplacement , options , resultType );
1064
+ queryContext .getCollation (entityType ).orElse (null ), entityType , mappedReplacement , options ,
1065
+ projection );
1065
1066
1066
1067
if (saved != null ) {
1067
1068
maybeEmitEvent (new AfterSaveEvent <>(saved , mappedReplacement , collectionName ));
@@ -2499,7 +2500,8 @@ protected <T> T doFindOne(String collectionName, Document query, Document fields
2499
2500
MongoPersistentEntity <?> entity = mappingContext .getPersistentEntity (entityClass );
2500
2501
2501
2502
QueryContext queryContext = queryOperations .createQueryContext (new BasicQuery (query , fields ));
2502
- Document mappedFields = queryContext .getMappedFields (entity , entityClass , projectionFactory );
2503
+ Document mappedFields = queryContext .getMappedFields (entity ,
2504
+ EntityProjection .nonProjecting (entityClass ));
2503
2505
Document mappedQuery = queryContext .getMappedQuery (entity );
2504
2506
2505
2507
if (LOGGER .isDebugEnabled ()) {
@@ -2551,7 +2553,8 @@ protected <S, T> List<T> doFind(String collectionName, Document query, Document
2551
2553
MongoPersistentEntity <?> entity = mappingContext .getPersistentEntity (entityClass );
2552
2554
2553
2555
QueryContext queryContext = queryOperations .createQueryContext (new BasicQuery (query , fields ));
2554
- Document mappedFields = queryContext .getMappedFields (entity , entityClass , projectionFactory );
2556
+ Document mappedFields = queryContext .getMappedFields (entity ,
2557
+ EntityProjection .nonProjecting (entityClass ));
2555
2558
Document mappedQuery = queryContext .getMappedQuery (entity );
2556
2559
2557
2560
if (LOGGER .isDebugEnabled ()) {
@@ -2573,9 +2576,11 @@ <S, T> List<T> doFind(String collectionName, Document query, Document fields, Cl
2573
2576
Class <T > targetClass , CursorPreparer preparer ) {
2574
2577
2575
2578
MongoPersistentEntity <?> entity = mappingContext .getPersistentEntity (sourceClass );
2579
+ EntityProjection <T , S > projection = operations .introspectProjection (targetClass ,
2580
+ sourceClass );
2576
2581
2577
2582
QueryContext queryContext = queryOperations .createQueryContext (new BasicQuery (query , fields ));
2578
- Document mappedFields = queryContext .getMappedFields (entity , targetClass , projectionFactory );
2583
+ Document mappedFields = queryContext .getMappedFields (entity , projection );
2579
2584
Document mappedQuery = queryContext .getMappedQuery (entity );
2580
2585
2581
2586
if (LOGGER .isDebugEnabled ()) {
@@ -2584,9 +2589,10 @@ <S, T> List<T> doFind(String collectionName, Document query, Document fields, Cl
2584
2589
}
2585
2590
2586
2591
return executeFindMultiInternal (new FindCallback (mappedQuery , mappedFields , null ), preparer ,
2587
- new ProjectingReadCallback <>(mongoConverter , sourceClass , targetClass , collectionName ), collectionName );
2592
+ new ProjectingReadCallback <>(mongoConverter , projection , collectionName ), collectionName );
2588
2593
}
2589
2594
2595
+
2590
2596
/**
2591
2597
* Convert given {@link CollectionOptions} to a document and take the domain type information into account when
2592
2598
* creating a mapped schema for validation. <br />
@@ -2745,6 +2751,35 @@ protected <T> T doFindAndReplace(String collectionName, Document mappedQuery, Do
2745
2751
Document mappedSort , @ Nullable com .mongodb .client .model .Collation collation , Class <?> entityType ,
2746
2752
Document replacement , FindAndReplaceOptions options , Class <T > resultType ) {
2747
2753
2754
+ EntityProjection <T , ?> projection = operations .introspectProjection (resultType ,
2755
+ entityType );
2756
+
2757
+ return doFindAndReplace (collectionName , mappedQuery , mappedFields , mappedSort , collation , entityType , replacement ,
2758
+ options , projection );
2759
+ }
2760
+
2761
+ /**
2762
+ * Customize this part for findAndReplace.
2763
+ *
2764
+ * @param collectionName The name of the collection to perform the operation in.
2765
+ * @param mappedQuery the query to look up documents.
2766
+ * @param mappedFields the fields to project the result to.
2767
+ * @param mappedSort the sort to be applied when executing the query.
2768
+ * @param collation collation settings for the query. Can be {@literal null}.
2769
+ * @param entityType the source domain type.
2770
+ * @param replacement the replacement {@link Document}.
2771
+ * @param options applicable options.
2772
+ * @param projection the projection descriptor.
2773
+ * @return {@literal null} if object does not exist, {@link FindAndReplaceOptions#isReturnNew() return new} is
2774
+ * {@literal false} and {@link FindAndReplaceOptions#isUpsert() upsert} is {@literal false}.
2775
+ * @since 3.4
2776
+ */
2777
+ @ Nullable
2778
+ private <T > T doFindAndReplace (String collectionName , Document mappedQuery , Document mappedFields ,
2779
+ Document mappedSort , @ Nullable com .mongodb .client .model .Collation collation , Class <?> entityType ,
2780
+ Document replacement , FindAndReplaceOptions options ,
2781
+ EntityProjection <T , ?> projection ) {
2782
+
2748
2783
if (LOGGER .isDebugEnabled ()) {
2749
2784
LOGGER .debug (String .format (
2750
2785
"findAndReplace using query: %s fields: %s sort: %s for class: %s and replacement: %s " + "in collection: %s" ,
@@ -2754,7 +2789,7 @@ protected <T> T doFindAndReplace(String collectionName, Document mappedQuery, Do
2754
2789
2755
2790
return executeFindOneInternal (
2756
2791
new FindAndReplaceCallback (mappedQuery , mappedFields , mappedSort , replacement , collation , options ),
2757
- new ProjectingReadCallback <>(mongoConverter , entityType , resultType , collectionName ), collectionName );
2792
+ new ProjectingReadCallback <>(mongoConverter , projection , collectionName ), collectionName );
2758
2793
}
2759
2794
2760
2795
/**
@@ -3205,17 +3240,15 @@ public T doWith(Document document) {
3205
3240
*/
3206
3241
private class ProjectingReadCallback <S , T > implements DocumentCallback <T > {
3207
3242
3208
- private final EntityReader <Object , Bson > reader ;
3209
- private final Class <S > entityType ;
3210
- private final Class <T > targetType ;
3243
+ private final MongoConverter reader ;
3244
+ private final EntityProjection <T , S > projection ;
3211
3245
private final String collectionName ;
3212
3246
3213
- ProjectingReadCallback (EntityReader < Object , Bson > reader , Class < S > entityType , Class < T > targetType ,
3247
+ ProjectingReadCallback (MongoConverter reader , EntityProjection < T , S > projection ,
3214
3248
String collectionName ) {
3215
3249
3216
3250
this .reader = reader ;
3217
- this .entityType = entityType ;
3218
- this .targetType = targetType ;
3251
+ this .projection = projection ;
3219
3252
this .collectionName = collectionName ;
3220
3253
}
3221
3254
@@ -3230,21 +3263,16 @@ public T doWith(Document document) {
3230
3263
return null ;
3231
3264
}
3232
3265
3233
- Class <?> typeToRead = targetType .isInterface () || targetType .isAssignableFrom (entityType ) ? entityType
3234
- : targetType ;
3266
+ maybeEmitEvent (new AfterLoadEvent <>(document , projection .getMappedType ().getType (), collectionName ));
3235
3267
3236
- maybeEmitEvent (new AfterLoadEvent <>(document , targetType , collectionName ));
3237
-
3238
- Object entity = reader .read (typeToRead , document );
3268
+ Object entity = reader .project (projection , document );
3239
3269
3240
3270
if (entity == null ) {
3241
3271
throw new MappingException (String .format ("EntityReader %s returned null" , reader ));
3242
3272
}
3243
3273
3244
- Object result = targetType .isInterface () ? projectionFactory .createProjection (targetType , entity ) : entity ;
3245
-
3246
- maybeEmitEvent (new AfterConvertEvent <>(document , result , collectionName ));
3247
- return (T ) maybeCallAfterConvert (result , document , collectionName );
3274
+ maybeEmitEvent (new AfterConvertEvent <>(document , entity , collectionName ));
3275
+ return (T ) maybeCallAfterConvert (entity , document , collectionName );
3248
3276
}
3249
3277
}
3250
3278
0 commit comments