From 46ece81d005b096901b93b9cb3bb3f33f8398428 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 11 Aug 2025 08:45:24 +0200 Subject: [PATCH] Polishing. Reformat code. Use existing SimpleTypeHolder instead of static MongoSimpleTypes. See: #5027 Original pull request: #5038 --- .../data/mongodb/core/MongoTemplate.java | 80 +++++++++---------- .../data/mongodb/core/QueryOperations.java | 2 +- .../repository/aot/AggregationBlocks.java | 37 ++++++--- .../repository/aot/AotPlaceholders.java | 3 +- .../repository/aot/AotQueryCreator.java | 33 ++++---- .../repository/aot/AotStringQuery.java | 10 +-- .../MongoAotRepositoryFragmentSupport.java | 1 - .../repository/aot/MongoCodeBlocks.java | 9 ++- .../aot/MongoRepositoryContributor.java | 31 ++++--- .../data/mongodb/repository/aot/Snippet.java | 1 - .../repository/query/MongoQueryCreator.java | 2 +- .../core/aggregation/AggregationTests.java | 42 +++------- 12 files changed, 119 insertions(+), 132 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index 895288d88..b46f0f93c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -111,11 +111,9 @@ import org.springframework.data.mongodb.core.query.UpdateDefinition.ArrayFilter; import org.springframework.data.mongodb.core.timeseries.Granularity; import org.springframework.data.mongodb.core.validation.Validator; import org.springframework.data.projection.EntityProjection; -import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.util.CloseableIterator; import org.springframework.data.util.Lazy; import org.springframework.data.util.Optionals; -import org.springframework.data.util.TypeInformation; import org.springframework.lang.Contract; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -498,7 +496,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, return doStream(query, entityType, collectionName, returnType, QueryResultConverter.entity()); } - @SuppressWarnings({"ConstantConditions", "NullAway"}) + @SuppressWarnings({ "ConstantConditions", "NullAway" }) Stream doStream(Query query, Class entityType, String collectionName, Class returnType, QueryResultConverter resultConverter) { @@ -523,8 +521,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, DocumentCallback resultReader = getResultReader(projection, collectionName, resultConverter); - return new CloseableIterableCursorAdapter<>(cursor, exceptionTranslator, - resultReader).stream(); + return new CloseableIterableCursorAdapter<>(cursor, exceptionTranslator, resultReader).stream(); }); } @@ -1152,7 +1149,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, @Override public @Nullable T findAndModify(Query query, UpdateDefinition update, FindAndModifyOptions options, - Class entityClass, String collectionName) { + Class entityClass, String collectionName) { return findAndModify(query, update, options, entityClass, collectionName, QueryResultConverter.entity()); } @@ -1182,12 +1179,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, @Override public @Nullable T findAndReplace(Query query, S replacement, FindAndReplaceOptions options, - Class entityType, String collectionName, Class resultType) { - return findAndReplace(query, replacement, options, entityType, collectionName, resultType, QueryResultConverter.entity()); + Class entityType, String collectionName, Class resultType) { + return findAndReplace(query, replacement, options, entityType, collectionName, resultType, + QueryResultConverter.entity()); } - @Nullable R findAndReplace(Query query, S replacement, FindAndReplaceOptions options, - Class entityType, String collectionName, Class resultType, QueryResultConverter resultConverter) { + @Nullable R findAndReplace(Query query, S replacement, FindAndReplaceOptions options, Class entityType, + String collectionName, Class resultType, QueryResultConverter resultConverter) { Assert.notNull(query, "Query must not be null"); Assert.notNull(replacement, "Replacement must not be null"); @@ -1215,7 +1213,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, maybeCallBeforeSave(replacement, mappedReplacement, collectionName); R saved = doFindAndReplace(collectionPreparer, collectionName, mappedQuery, mappedFields, mappedSort, - queryContext.getCollation(entityType).orElse(null), entityType, mappedReplacement, options, projection, resultConverter); + queryContext.getCollation(entityType).orElse(null), entityType, mappedReplacement, options, projection, + resultConverter); if (saved != null) { maybeEmitEvent(new AfterSaveEvent<>(saved, mappedReplacement, collectionName)); @@ -1508,7 +1507,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, initialized = maybeCallBeforeSave(initialized, document, collectionName); MappedDocument mappedDocument = queryOperations.createInsertContext(MappedDocument.of(document)) - .prepareId(uninitialized.getClass()); + .prepareId(uninitialized.getClass()); documentList.add(mappedDocument.getDocument()); initializedBatchToSave.add(initialized); @@ -2221,14 +2220,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, } }; - List result = doFind(collectionName, createDelegate(query), query.getQueryObject(), query.getFieldsObject(), entityClass, - new QueryCursorPreparer(query, entityClass), callback); + List result = doFind(collectionName, createDelegate(query), query.getQueryObject(), query.getFieldsObject(), + entityClass, new QueryCursorPreparer(query, entityClass), callback); if (!CollectionUtils.isEmpty(result)) { Criteria[] criterias = ids.stream() // - .map(it -> Criteria.where("_id").is(it)) // - .toArray(Criteria[]::new); + .map(it -> Criteria.where("_id").is(it)) // + .toArray(Criteria[]::new); Query removeQuery = new Query(criterias.length == 1 ? criterias[0] : new Criteria().orOperator(criterias)); if (query.hasReadPreference()) { @@ -2270,20 +2269,19 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, return doAggregate(aggregation, collectionName, outputType, QueryResultConverter.entity(), context); } - @SuppressWarnings({"ConstantConditions", "NullAway"}) + @SuppressWarnings({ "ConstantConditions", "NullAway" }) AggregationResults doAggregate(Aggregation aggregation, String collectionName, Class outputType, QueryResultConverter resultConverter, AggregationOperationContext context) { final DocumentCallback callback; - if(aggregation instanceof TypedAggregation ta && outputType.isInterface()) { + if (aggregation instanceof TypedAggregation ta && outputType.isInterface()) { EntityProjection projection = operations.introspectProjection(outputType, ta.getInputType()); ProjectingReadCallback cb = new ProjectingReadCallback(mongoConverter, projection, collectionName); - callback = new QueryResultConverterCallback<>(resultConverter, - cb); + callback = new QueryResultConverterCallback<>(resultConverter, cb); } else { callback = new QueryResultConverterCallback<>(resultConverter, - new ReadDocumentCallback<>(mongoConverter, outputType, collectionName)); + new ReadDocumentCallback<>(mongoConverter, outputType, collectionName)); } AggregationOptions options = aggregation.getOptions(); @@ -2370,8 +2368,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, @SuppressWarnings({ "ConstantConditions", "NullAway" }) Stream doAggregateStream(Aggregation aggregation, String collectionName, Class outputType, - QueryResultConverter resultConverter, - @Nullable AggregationOperationContext context) { + QueryResultConverter resultConverter, @Nullable AggregationOperationContext context) { Assert.notNull(aggregation, "Aggregation pipeline must not be null"); Assert.hasText(collectionName, "Collection name must not be null or empty"); @@ -2649,9 +2646,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, * @return the converted object or {@literal null} if none exists. */ @Nullable - protected T doFindOne(String collectionName, - CollectionPreparer> collectionPreparer, Document query, Document fields, - Class entityClass) { + protected T doFindOne(String collectionName, CollectionPreparer> collectionPreparer, + Document query, Document fields, Class entityClass) { return doFindOne(collectionName, collectionPreparer, query, fields, CursorPreparer.NO_OP_PREPARER, entityClass); } @@ -2670,9 +2666,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, */ @Nullable @SuppressWarnings("ConstantConditions") - protected T doFindOne(String collectionName, - CollectionPreparer> collectionPreparer, Document query, Document fields, - CursorPreparer preparer, Class entityClass) { + protected T doFindOne(String collectionName, CollectionPreparer> collectionPreparer, + Document query, Document fields, CursorPreparer preparer, Class entityClass) { MongoPersistentEntity entity = mappingContext.getPersistentEntity(entityClass); @@ -2870,9 +2865,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, @SuppressWarnings("ConstantConditions") @Nullable T doFindAndModify(CollectionPreparer> collectionPreparer, - String collectionName, - Document query, @Nullable Document fields, @Nullable Document sort, Class entityClass, UpdateDefinition update, - @Nullable FindAndModifyOptions options, QueryResultConverter resultConverter) { + String collectionName, Document query, @Nullable Document fields, @Nullable Document sort, Class entityClass, + UpdateDefinition update, @Nullable FindAndModifyOptions options, + QueryResultConverter resultConverter) { if (options == null) { options = new FindAndModifyOptions(); @@ -2894,7 +2889,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, serializeToJsonSafely(mappedUpdate), collectionName)); } - DocumentCallback callback = getResultReader(EntityProjection.nonProjecting(entityClass), collectionName, resultConverter); + DocumentCallback callback = getResultReader(EntityProjection.nonProjecting(entityClass), collectionName, + resultConverter); return executeFindOneInternal( new FindAndModifyCallback(collectionPreparer, mappedQuery, fields, sort, mappedUpdate, @@ -2919,8 +2915,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, */ @Nullable protected T doFindAndReplace(CollectionPreparer> collectionPreparer, - String collectionName, - Document mappedQuery, Document mappedFields, Document mappedSort, + String collectionName, Document mappedQuery, Document mappedFields, Document mappedSort, com.mongodb.client.model.@Nullable Collation collation, Class entityType, Document replacement, FindAndReplaceOptions options, Class resultType) { @@ -2963,10 +2958,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, */ @Nullable private R doFindAndReplace(CollectionPreparer> collectionPreparer, - String collectionName, - Document mappedQuery, Document mappedFields, Document mappedSort, + String collectionName, Document mappedQuery, Document mappedFields, Document mappedSort, com.mongodb.client.model.@Nullable Collation collation, Class entityType, Document replacement, - FindAndReplaceOptions options, EntityProjection projection, QueryResultConverter resultConverter) { + FindAndReplaceOptions options, EntityProjection projection, + QueryResultConverter resultConverter) { if (LOGGER.isDebugEnabled()) { LOGGER @@ -2979,8 +2974,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, DocumentCallback callback = getResultReader(projection, collectionName, resultConverter); return executeFindOneInternal(new FindAndReplaceCallback(collectionPreparer, mappedQuery, mappedFields, mappedSort, - replacement, collation, options),callback, - collectionName); + replacement, collation, options), callback, collectionName); } @SuppressWarnings("NullAway") @@ -3158,8 +3152,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, return getMappedSortObject(sortObject, mappingContext.getPersistentEntity(type)); } - - private @Nullable Document getMappedSortObject(@Nullable Document sortObject, @Nullable MongoPersistentEntity entity) { + private @Nullable Document getMappedSortObject(@Nullable Document sortObject, + @Nullable MongoPersistentEntity entity) { if (ObjectUtils.isEmpty(sortObject)) { return null; @@ -3392,7 +3386,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, private final Document fields; private final Document sort; private final Document update; - private final com.mongodb.client.model.@Nullable Collation collation; + private final com.mongodb.client.model.@Nullable Collation collation; private final FindAndReplaceOptions options; FindAndReplaceCallback(CollectionPreparer> collectionPreparer, Document query, diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java index 24e2c99a6..743a84351 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java @@ -377,7 +377,7 @@ class QueryOperations { mappedFields = queryMapper.getMappedFields(fields, entity); } else { mappedFields = propertyOperations.computeMappedFieldsForProjection(projection, fields); - if(projection.getMappedType().getType().isInterface()) { + if (projection.getMappedType().getType().isInterface()) { mappedFields = queryMapper.getMappedFields(mappedFields, entity); } mappedFields = queryMapper.addMetaAttributes(mappedFields, entity); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AggregationBlocks.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AggregationBlocks.java index c376fb11f..38ac76c0b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AggregationBlocks.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AggregationBlocks.java @@ -22,10 +22,12 @@ import java.util.stream.Stream; import org.bson.Document; import org.jspecify.annotations.NullUnmarked; + import org.springframework.core.ResolvableType; import org.springframework.core.annotation.MergedAnnotation; import org.springframework.data.domain.SliceImpl; import org.springframework.data.domain.Sort.Order; +import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.aggregation.Aggregation; import org.springframework.data.mongodb.core.aggregation.AggregationOperation; @@ -33,7 +35,6 @@ import org.springframework.data.mongodb.core.aggregation.AggregationOptions; import org.springframework.data.mongodb.core.aggregation.AggregationPipeline; import org.springframework.data.mongodb.core.aggregation.AggregationResults; import org.springframework.data.mongodb.core.aggregation.TypedAggregation; -import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes; import org.springframework.data.mongodb.core.query.Collation; import org.springframework.data.mongodb.repository.Hint; import org.springframework.data.mongodb.repository.ReadPreference; @@ -58,12 +59,15 @@ class AggregationBlocks { static class AggregationExecutionCodeBlockBuilder { private final AotQueryMethodGenerationContext context; + private final SimpleTypeHolder simpleTypeHolder; private final MongoQueryMethod queryMethod; private String aggregationVariableName; - AggregationExecutionCodeBlockBuilder(AotQueryMethodGenerationContext context, MongoQueryMethod queryMethod) { + AggregationExecutionCodeBlockBuilder(AotQueryMethodGenerationContext context, SimpleTypeHolder simpleTypeHolder, + MongoQueryMethod queryMethod) { this.context = context; + this.simpleTypeHolder = simpleTypeHolder; this.queryMethod = queryMethod; } @@ -80,7 +84,7 @@ class AggregationBlocks { builder.add("\n"); - Class outputType = getOutputType(queryMethod); + Class outputType = getOutputType(simpleTypeHolder, queryMethod); if (ReflectionUtils.isVoid(queryMethod.getReturnedObjectType())) { builder.addStatement("$L.aggregate($L, $T.class)", mongoOpsRef, aggregationVariableName, outputType); @@ -152,13 +156,19 @@ class AggregationBlocks { } - private static Class getOutputType(MongoQueryMethod queryMethod) { + private static Class getOutputType(SimpleTypeHolder simpleTypeHolder, MongoQueryMethod queryMethod) { + Class outputType = queryMethod.getReturnedObjectType(); - if (MongoSimpleTypes.HOLDER.isSimpleType(outputType)) { - outputType = Document.class; - } else if (ClassUtils.isAssignable(AggregationResults.class, outputType) && queryMethod.getReturnType().getComponentType() != null) { - outputType = queryMethod.getReturnType().getComponentType().getType(); + + if (simpleTypeHolder.isSimpleType(outputType)) { + return Document.class; } + + if (ClassUtils.isAssignable(AggregationResults.class, outputType) + && queryMethod.getReturnType().getComponentType() != null) { + return queryMethod.getReturnType().getComponentType().getType(); + } + return outputType; } @@ -166,6 +176,7 @@ class AggregationBlocks { static class AggregationCodeBlockBuilder { private final AotQueryMethodGenerationContext context; + private final SimpleTypeHolder simpleTypeHolder; private final MongoQueryMethod queryMethod; private final String parameterNames; @@ -174,9 +185,11 @@ class AggregationBlocks { private String aggregationVariableName; private boolean pipelineOnly; - AggregationCodeBlockBuilder(AotQueryMethodGenerationContext context, MongoQueryMethod queryMethod) { + AggregationCodeBlockBuilder(AotQueryMethodGenerationContext context, SimpleTypeHolder simpleTypeHolder, + MongoQueryMethod queryMethod) { this.context = context; + this.simpleTypeHolder = simpleTypeHolder; this.queryMethod = queryMethod; this.parameterNames = StringUtils.collectionToDelimitedString(context.getAllParameterNames(), ", "); } @@ -230,7 +243,7 @@ class AggregationBlocks { builder.add(aggregationStages(context.localVariable("stages"), source.stages())); if (StringUtils.hasText(sortParameter)) { - Class outputType = getOutputType(queryMethod); + Class outputType = getOutputType(simpleTypeHolder, queryMethod); builder.add(sortingStage(sortParameter, outputType)); } @@ -324,7 +337,7 @@ class AggregationBlocks { context.localVariable("sortDocument"), context.localVariable("order")); builder.endControlFlow(); - if (outputType == Document.class || MongoSimpleTypes.HOLDER.isSimpleType(outputType) + if (outputType == Document.class || simpleTypeHolder.isSimpleType(outputType) || ClassUtils.isAssignable(context.getRepositoryInformation().getDomainType(), outputType)) { builder.addStatement("$L.add(new $T($S, $L))", context.localVariable("stages"), Document.class, "$sort", context.localVariable("sortDocument")); @@ -343,7 +356,7 @@ class AggregationBlocks { Builder builder = CodeBlock.builder(); - builder.add(sortingStage(pageableProvider + ".getSort()", getOutputType(queryMethod))); + builder.add(sortingStage(pageableProvider + ".getSort()", getOutputType(simpleTypeHolder, queryMethod))); builder.beginControlFlow("if ($L.isPaged())", pageableProvider); builder.beginControlFlow("if ($L.getOffset() > 0)", pageableProvider); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AotPlaceholders.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AotPlaceholders.java index b6cbe5083..5d4e45fa6 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AotPlaceholders.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AotPlaceholders.java @@ -279,7 +279,8 @@ class AotPlaceholders { this.options = options; } - @Nullable String regexOptions() { + @Nullable + String regexOptions() { return options; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AotQueryCreator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AotQueryCreator.java index b0c998e65..c3d23af9d 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AotQueryCreator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AotQueryCreator.java @@ -68,13 +68,7 @@ import com.mongodb.DBRef; * @author Christoph Strobl * @since 5.0 */ -class AotQueryCreator { - - private final MappingContext mappingContext; - - public AotQueryCreator(MappingContext mappingContext) { - this.mappingContext = mappingContext; - } +record AotQueryCreator(MappingContext mappingContext) { @SuppressWarnings("NullAway") AotStringQuery createQuery(PartTree partTree, QueryMethod queryMethod, Method source) { @@ -129,7 +123,7 @@ class AotQueryCreator { return criteria.is(param); } - if(part.getType().equals(Type.NOT_LIKE)) { + if (part.getType().equals(Type.NOT_LIKE)) { return criteria.raw("$not", param); } @@ -179,15 +173,16 @@ class AotQueryCreator { private final List placeholders; - @Nullable Part getPartForIndex(PartTree partTree, Parameter parameter) { - if(!parameter.isBindable()) { + @Nullable + Part getPartForIndex(PartTree partTree, Parameter parameter) { + if (!parameter.isBindable()) { return null; } List parts = partTree.getParts().stream().toList(); - int counter = 0; + int counter = 0; for (Part part : parts) { - if(counter == parameter.getIndex()) { + if (counter == parameter.getIndex()) { return part; } counter += part.getNumberOfArguments(); @@ -196,17 +191,14 @@ class AotQueryCreator { } public PlaceholderParameterAccessor(PartTree partTree, QueryMethod queryMethod) { - if (queryMethod.getParameters().getNumberOfParameters() == 0) { placeholders = List.of(); } else { - placeholders = new ArrayList<>(); Parameters parameters = queryMethod.getParameters(); - for (Parameter parameter : parameters.toList()) { if (ClassUtils.isAssignable(GeoJson.class, parameter.getType())) { placeholders.add(parameter.getIndex(), AotPlaceholders.geoJson(parameter.getIndex(), "")); @@ -224,8 +216,15 @@ class AotQueryCreator { placeholders.add(parameter.getIndex(), AotPlaceholders.regex(parameter.getIndex(), null)); } else { Part partForIndex = getPartForIndex(partTree, parameter); - if(partForIndex != null && (partForIndex.getType().equals(Type.LIKE) || partForIndex.getType().equals(Type.NOT_LIKE))) { - placeholders.add(parameter.getIndex(), AotPlaceholders.regex(parameter.getIndex(), partForIndex.shouldIgnoreCase().equals(IgnoreCaseType.ALWAYS) || partForIndex.shouldIgnoreCase().equals(IgnoreCaseType.WHEN_POSSIBLE) ? "i": null)); + if (partForIndex != null + && (partForIndex.getType().equals(Type.LIKE) || partForIndex.getType().equals(Type.NOT_LIKE))) { + placeholders + .add(parameter.getIndex(), + AotPlaceholders + .regex(parameter.getIndex(), + partForIndex.shouldIgnoreCase().equals(IgnoreCaseType.ALWAYS) + || partForIndex.shouldIgnoreCase().equals(IgnoreCaseType.WHEN_POSSIBLE) ? "i" + : null)); } else { placeholders.add(parameter.getIndex(), AotPlaceholders.indexed(parameter.getIndex())); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AotStringQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AotStringQuery.java index c0920ba77..4bc953ae5 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AotStringQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/AotStringQuery.java @@ -28,7 +28,6 @@ import org.springframework.data.mongodb.core.query.Collation; import org.springframework.data.mongodb.core.query.Field; import org.springframework.data.mongodb.core.query.Meta; import org.springframework.data.mongodb.core.query.Query; -import org.springframework.data.mongodb.repository.aot.AotPlaceholders.Placeholder; import org.springframework.data.mongodb.repository.aot.AotPlaceholders.RegexPlaceholder; import org.springframework.util.StringUtils; @@ -80,19 +79,20 @@ class AotStringQuery extends Query { } boolean isRegexPlaceholderAt(int index) { - if(this.placeholders.isEmpty()) { + if (this.placeholders.isEmpty()) { return false; } return this.placeholders.get(index) instanceof RegexPlaceholder; } - @Nullable String getRegexOptions(int index) { - if(this.placeholders.isEmpty()) { + @Nullable + String getRegexOptions(int index) { + if (this.placeholders.isEmpty()) { return null; } - return this.placeholders.get(index) instanceof RegexPlaceholder rgp ? rgp.regexOptions() : null; + return this.placeholders.get(index) instanceof RegexPlaceholder rgp ? rgp.regexOptions() : null; } @Override diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoAotRepositoryFragmentSupport.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoAotRepositoryFragmentSupport.java index 83c96e549..69837f59a 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoAotRepositoryFragmentSupport.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoAotRepositoryFragmentSupport.java @@ -189,7 +189,6 @@ public class MongoAotRepositoryFragmentSupport { criteria.lt(value); } } - }; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoCodeBlocks.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoCodeBlocks.java index ee74c76ec..5fd577e1f 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoCodeBlocks.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoCodeBlocks.java @@ -20,6 +20,7 @@ import java.util.regex.Pattern; import org.bson.Document; import org.jspecify.annotations.Nullable; import org.springframework.core.annotation.MergedAnnotation; +import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.mongodb.repository.ReadPreference; import org.springframework.data.mongodb.repository.aot.AggregationBlocks.AggregationCodeBlockBuilder; import org.springframework.data.mongodb.repository.aot.AggregationBlocks.AggregationExecutionCodeBlockBuilder; @@ -118,24 +119,28 @@ class MongoCodeBlocks { * Builder for generating aggregation (pipeline) parsing {@link CodeBlock}. * * @param context + * @param simpleTypeHolder * @param queryMethod * @return */ static AggregationCodeBlockBuilder aggregationBlockBuilder(AotQueryMethodGenerationContext context, + SimpleTypeHolder simpleTypeHolder, MongoQueryMethod queryMethod) { - return new AggregationCodeBlockBuilder(context, queryMethod); + return new AggregationCodeBlockBuilder(context, simpleTypeHolder, queryMethod); } /** * Builder for generating aggregation execution {@link CodeBlock}. * * @param context + * @param simpleTypeHolder * @param queryMethod * @return */ static AggregationExecutionCodeBlockBuilder aggregationExecutionBlockBuilder(AotQueryMethodGenerationContext context, + SimpleTypeHolder simpleTypeHolder, MongoQueryMethod queryMethod) { - return new AggregationExecutionCodeBlockBuilder(context, queryMethod); + return new AggregationExecutionCodeBlockBuilder(context, simpleTypeHolder, queryMethod); } /** diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoRepositoryContributor.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoRepositoryContributor.java index 0da74d06f..1cba607cc 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoRepositoryContributor.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/MongoRepositoryContributor.java @@ -28,6 +28,7 @@ import org.jspecify.annotations.Nullable; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.aggregation.AggregationUpdate; import org.springframework.data.mongodb.core.convert.MongoCustomConversions; @@ -68,6 +69,7 @@ public class MongoRepositoryContributor extends RepositoryContributor { private static final Log logger = LogFactory.getLog(MongoRepositoryContributor.class); private final AotQueryCreator queryCreator; + private final SimpleTypeHolder simpleTypeHolder; private final MongoMappingContext mappingContext; private final NamedQueries namedQueries; @@ -85,8 +87,10 @@ public class MongoRepositoryContributor extends RepositoryContributor { MongoCustomConversions mongoCustomConversions = MongoCustomConversions .create(MongoCustomConversions.MongoConverterConfigurationAdapter::useNativeDriverJavaTimeCodecs); + this.simpleTypeHolder = mongoCustomConversions.getSimpleTypeHolder(); + this.mappingContext = new MongoMappingContext(); - this.mappingContext.setSimpleTypeHolder(mongoCustomConversions.getSimpleTypeHolder()); + this.mappingContext.setSimpleTypeHolder(this.simpleTypeHolder); this.mappingContext.setAutoIndexCreation(false); this.mappingContext.afterPropertiesSet(); @@ -150,7 +154,7 @@ public class MongoRepositoryContributor extends RepositoryContributor { if (queryMethod.hasAnnotatedAggregation()) { AggregationInteraction aggregation = new AggregationInteraction(queryMethod.getAnnotatedAggregation()); queryMetadata = aggregation; - contribution = aggregationMethodContributor(queryMethod, aggregation); + contribution = aggregationMethodContributor(queryMethod, simpleTypeHolder, aggregation); } else { QueryInteraction query = createStringQuery(getRepositoryInformation(), queryMethod, @@ -193,7 +197,7 @@ public class MongoRepositoryContributor extends RepositoryContributor { if (!ObjectUtils.isEmpty(updateSource.pipeline())) { AggregationUpdateInteraction update = new AggregationUpdateInteraction(query, updateSource.pipeline()); queryMetadata = update; - contribution = aggregationUpdateMethodContributor(queryMethod, update); + contribution = aggregationUpdateMethodContributor(queryMethod, simpleTypeHolder, update); } } } else { @@ -210,17 +214,7 @@ public class MongoRepositoryContributor extends RepositoryContributor { return MethodContributor.forQueryMethod(queryMethod).metadataOnly(queryMetadata); } - MethodContributor.RepositoryMethodContribution finalContribution = contribution; - - return MethodContributor.forQueryMethod(queryMethod).withMetadata(queryMetadata).contribute(context -> { - - CodeBlock.Builder builder = CodeBlock.builder(); - -// builder.addStatement("class ExpressionMarker{}"); - builder.add(finalContribution.contribute(context)); - - return builder.build(); - }); + return MethodContributor.forQueryMethod(queryMethod).withMetadata(queryMetadata).contribute(contribution); } @SuppressWarnings("NullAway") @@ -289,6 +283,7 @@ public class MongoRepositoryContributor extends RepositoryContributor { } static MethodContributor.RepositoryMethodContribution aggregationMethodContributor(MongoQueryMethod queryMethod, + SimpleTypeHolder simpleTypeHolder, AggregationInteraction aggregation) { return context -> { @@ -297,9 +292,10 @@ public class MongoRepositoryContributor extends RepositoryContributor { String variableName = context.localVariable("aggregation"); - builder.add(aggregationBlockBuilder(context, queryMethod).stages(aggregation) + builder.add(aggregationBlockBuilder(context, simpleTypeHolder, queryMethod).stages(aggregation) .usingAggregationVariableName(variableName).build()); - builder.add(aggregationExecutionBlockBuilder(context, queryMethod).referencing(variableName).build()); + builder.add( + aggregationExecutionBlockBuilder(context, simpleTypeHolder, queryMethod).referencing(variableName).build()); return builder.build(); }; @@ -351,6 +347,7 @@ public class MongoRepositoryContributor extends RepositoryContributor { } static MethodContributor.RepositoryMethodContribution aggregationUpdateMethodContributor(MongoQueryMethod queryMethod, + SimpleTypeHolder simpleTypeHolder, AggregationUpdateInteraction update) { return context -> { @@ -364,7 +361,7 @@ public class MongoRepositoryContributor extends RepositoryContributor { // update definition String updateVariableName = context.localVariable("updateDefinition"); - builder.add(aggregationBlockBuilder(context, queryMethod).stages(update) + builder.add(aggregationBlockBuilder(context, simpleTypeHolder, queryMethod).stages(update) .usingAggregationVariableName(updateVariableName).pipelineOnly(true).build()); builder.addStatement("$T $L = $T.from($L.getOperations())", AggregationUpdate.class, diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/Snippet.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/Snippet.java index 9fafdb171..6446544c3 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/Snippet.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/Snippet.java @@ -195,7 +195,6 @@ interface Snippet { public BuilderStyleBuilder with(Snippet snippet) { Assert.notNull(targetMethodName, "TargetMethodName must be set before calling this method"); - new BuilderStyleSnippet(targetVariableName, targetMethodName, snippet).appendTo(targetBuilder); return this; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java index 807dc518d..53f9a385c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryCreator.java @@ -375,7 +375,7 @@ public class MongoQueryCreator extends AbstractQueryCreator { "Argument for creating $regex pattern for property '%s' must not be null", part.getProperty().getSegment())); } - if(value instanceof Pattern pattern) { + if (value instanceof Pattern pattern) { return criteria.regex(pattern); } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java index c1d941036..f80871d35 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java @@ -15,31 +15,10 @@ */ package org.springframework.data.mongodb.core.aggregation; -import static org.springframework.data.domain.Sort.Direction.ASC; -import static org.springframework.data.domain.Sort.Direction.DESC; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.DEFAULT_CONTEXT; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.bind; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.bucket; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.bucketAuto; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.count; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.facet; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.group; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.limit; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.lookup; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.match; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregationOptions; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.out; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.previousOperation; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.project; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.replaceRoot; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.sample; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.skip; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.sort; -import static org.springframework.data.mongodb.core.aggregation.Aggregation.unwind; -import static org.springframework.data.mongodb.core.query.Criteria.where; -import static org.springframework.data.mongodb.test.util.Assertions.assertThat; -import static org.springframework.data.mongodb.test.util.Assertions.assertThatIllegalArgumentException; +import static org.springframework.data.domain.Sort.Direction.*; +import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; +import static org.springframework.data.mongodb.core.query.Criteria.*; +import static org.springframework.data.mongodb.test.util.Assertions.*; import java.io.BufferedInputStream; import java.text.ParseException; @@ -67,6 +46,7 @@ import org.bson.Document; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; + import org.springframework.core.io.ClassPathResource; import org.springframework.data.annotation.Id; import org.springframework.data.domain.Sort; @@ -574,7 +554,7 @@ public class AggregationTests { /* //complex mongodb aggregation framework example from https://docs.mongodb.org/manual/tutorial/aggregation-examples/#largest-and-smallest-cities-by-state - + db.zipcodes.aggregate( { $group: { @@ -3116,8 +3096,8 @@ public class AggregationTests { } } - @Test - void xxx() { + @Test // GH-5027 + void shouldAggregateAsInterface() { MyOhMy source = new MyOhMy(); source.id = "id-1"; @@ -3127,8 +3107,8 @@ public class AggregationTests { mongoTemplate.save(source); TypedAggregation agg = newAggregation(MyOhMy.class, project("firstname")); - AggregationResults aggregate = mongoTemplate.aggregate(agg, MyMyOh.class); - assertThat(aggregate.getMappedResults()).hasOnlyElementsOfType(MyMyOh.class); + AggregationResults aggregate = mongoTemplate.aggregate(agg, MyMyOhInterface.class); + assertThat(aggregate.getMappedResults()).hasOnlyElementsOfType(MyMyOhInterface.class); } static class MyOhMy { @@ -3137,7 +3117,7 @@ public class AggregationTests { String lastname; } - interface MyMyOh { + interface MyMyOhInterface { String getFirstname(); } }