Browse Source

Adopt to Commons changes.

See: #4939
pull/4976/head
Mark Paluch 9 months ago
parent
commit
2aac1a59be
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 93
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/generated/MongoBlocks.java
  2. 72
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/generated/MongoRepositoryContributor.java
  3. 6
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java

93
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/generated/MongoBlocks.java

@ -18,10 +18,13 @@ package org.springframework.data.mongodb.aot.generated;
import java.lang.reflect.Parameter; import java.lang.reflect.Parameter;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.bson.Document; import org.bson.Document;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.data.mongodb.BindableMongoExpression; import org.springframework.data.mongodb.BindableMongoExpression;
import org.springframework.data.mongodb.core.ExecutableFindOperation.FindWithQuery; import org.springframework.data.mongodb.core.ExecutableFindOperation.FindWithQuery;
import org.springframework.data.mongodb.core.ExecutableRemoveOperation.ExecutableRemove; import org.springframework.data.mongodb.core.ExecutableRemoveOperation.ExecutableRemove;
@ -33,7 +36,8 @@ import org.springframework.data.mongodb.repository.query.MongoQueryExecution.Del
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.DeleteExecutionX.Type; import org.springframework.data.mongodb.repository.query.MongoQueryExecution.DeleteExecutionX.Type;
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.PagedExecution; import org.springframework.data.mongodb.repository.query.MongoQueryExecution.PagedExecution;
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.SlicedExecution; import org.springframework.data.mongodb.repository.query.MongoQueryExecution.SlicedExecution;
import org.springframework.data.repository.aot.generate.AotRepositoryMethodGenerationContext; import org.springframework.data.mongodb.repository.query.MongoQueryMethod;
import org.springframework.data.repository.aot.generate.AotQueryMethodGenerationContext;
import org.springframework.javapoet.ClassName; import org.springframework.javapoet.ClassName;
import org.springframework.javapoet.CodeBlock; import org.springframework.javapoet.CodeBlock;
import org.springframework.javapoet.CodeBlock.Builder; import org.springframework.javapoet.CodeBlock.Builder;
@ -50,25 +54,29 @@ public class MongoBlocks {
private static final Pattern PARAMETER_BINDING_PATTERN = Pattern.compile("\\?(\\d+)"); private static final Pattern PARAMETER_BINDING_PATTERN = Pattern.compile("\\?(\\d+)");
static QueryBlockBuilder queryBlockBuilder(AotRepositoryMethodGenerationContext context) { static QueryBlockBuilder queryBlockBuilder(AotQueryMethodGenerationContext context, MongoQueryMethod queryMethod) {
return new QueryBlockBuilder(context); return new QueryBlockBuilder(context, queryMethod);
} }
static QueryExecutionBlockBuilder queryExecutionBlockBuilder(AotRepositoryMethodGenerationContext context) { static QueryExecutionBlockBuilder queryExecutionBlockBuilder(AotQueryMethodGenerationContext context,
return new QueryExecutionBlockBuilder(context); MongoQueryMethod queryMethod) {
return new QueryExecutionBlockBuilder(context, queryMethod);
} }
static DeleteExecutionBuilder deleteExecutionBlockBuilder(AotRepositoryMethodGenerationContext context) { static DeleteExecutionBuilder deleteExecutionBlockBuilder(AotQueryMethodGenerationContext context,
return new DeleteExecutionBuilder(context); MongoQueryMethod queryMethod) {
return new DeleteExecutionBuilder(context, queryMethod);
} }
static class DeleteExecutionBuilder { static class DeleteExecutionBuilder {
AotRepositoryMethodGenerationContext context; private final AotQueryMethodGenerationContext context;
private final MongoQueryMethod queryMethod;
String queryVariableName; String queryVariableName;
public DeleteExecutionBuilder(AotRepositoryMethodGenerationContext context) { public DeleteExecutionBuilder(AotQueryMethodGenerationContext context, MongoQueryMethod queryMethod) {
this.context = context; this.context = context;
this.queryMethod = queryMethod;
} }
public DeleteExecutionBuilder referencing(String queryVariableName) { public DeleteExecutionBuilder referencing(String queryVariableName) {
@ -85,15 +93,16 @@ public class MongoBlocks {
&& !ObjectUtils.nullSafeEquals(TypeName.get(context.getRepositoryInformation().getDomainType()), && !ObjectUtils.nullSafeEquals(TypeName.get(context.getRepositoryInformation().getDomainType()),
context.getActualReturnType()); context.getActualReturnType());
Object actualReturnType = isProjecting ? context.getActualReturnType() Object actualReturnType = isProjecting ? context.getActualReturnType().getType()
: context.getRepositoryInformation().getDomainType(); : context.getRepositoryInformation().getDomainType();
builder.add("\n"); builder.add("\n");
builder.addStatement("$T<$T> remover = $L.remove($T.class)", ExecutableRemove.class, actualReturnType, builder.addStatement("$T<$T> remover = $L.remove($T.class)", ExecutableRemove.class,
context.getRepositoryInformation().getDomainType(),
mongoOpsRef, context.getRepositoryInformation().getDomainType()); mongoOpsRef, context.getRepositoryInformation().getDomainType());
Type type = Type.FIND_AND_REMOVE_ALL; Type type = Type.FIND_AND_REMOVE_ALL;
if (context.returnsSingleValue()) { if (!queryMethod.isCollectionQuery()) {
if (!ClassUtils.isPrimitiveOrWrapper(context.getMethod().getReturnType())) { if (!ClassUtils.isPrimitiveOrWrapper(context.getMethod().getReturnType())) {
type = Type.FIND_AND_REMOVE_ONE; type = Type.FIND_AND_REMOVE_ONE;
} else { } else {
@ -103,7 +112,7 @@ public class MongoBlocks {
actualReturnType = ClassUtils.isPrimitiveOrWrapper(context.getMethod().getReturnType()) actualReturnType = ClassUtils.isPrimitiveOrWrapper(context.getMethod().getReturnType())
? ClassName.get(context.getMethod().getReturnType()) ? ClassName.get(context.getMethod().getReturnType())
: context.returnsSingleValue() ? actualReturnType : context.getReturnType(); : queryMethod.isCollectionQuery() ? context.getReturnTypeName() : actualReturnType;
builder.addStatement("return ($T) new $T(remover, $T.$L).execute($L)", actualReturnType, DeleteExecutionX.class, builder.addStatement("return ($T) new $T(remover, $T.$L).execute($L)", actualReturnType, DeleteExecutionX.class,
DeleteExecutionX.Type.class, type.name(), queryVariableName); DeleteExecutionX.Type.class, type.name(), queryVariableName);
@ -114,11 +123,14 @@ public class MongoBlocks {
static class QueryExecutionBlockBuilder { static class QueryExecutionBlockBuilder {
AotRepositoryMethodGenerationContext context; private final AotQueryMethodGenerationContext context;
private final MongoQueryMethod queryMethod;
private String queryVariableName; private String queryVariableName;
private boolean count, exists;
public QueryExecutionBlockBuilder(AotRepositoryMethodGenerationContext context) { public QueryExecutionBlockBuilder(AotQueryMethodGenerationContext context, MongoQueryMethod queryMethod) {
this.context = context; this.context = context;
this.queryMethod = queryMethod;
} }
QueryExecutionBlockBuilder referencing(String queryVariableName) { QueryExecutionBlockBuilder referencing(String queryVariableName) {
@ -127,16 +139,24 @@ public class MongoBlocks {
return this; return this;
} }
QueryExecutionBlockBuilder count(boolean count) {
this.count = count;
return this;
}
QueryExecutionBlockBuilder exists(boolean exists) {
this.exists = exists;
return this;
}
CodeBlock build() { CodeBlock build() {
String mongoOpsRef = context.fieldNameOf(MongoOperations.class); String mongoOpsRef = context.fieldNameOf(MongoOperations.class);
Builder builder = CodeBlock.builder(); Builder builder = CodeBlock.builder();
boolean isProjecting = context.getActualReturnType() != null boolean isProjecting = context.getReturnedType().isProjecting();
&& !ObjectUtils.nullSafeEquals(TypeName.get(context.getRepositoryInformation().getDomainType()), Object actualReturnType = isProjecting ? context.getActualReturnType().getType()
context.getActualReturnType());
Object actualReturnType = isProjecting ? context.getActualReturnType()
: context.getRepositoryInformation().getDomainType(); : context.getRepositoryInformation().getDomainType();
builder.add("\n"); builder.add("\n");
@ -150,24 +170,23 @@ public class MongoBlocks {
context.getRepositoryInformation().getDomainType()); context.getRepositoryInformation().getDomainType());
} }
String terminatingMethod = "all()"; String terminatingMethod;
if (context.returnsSingleValue()) {
if (context.returnsOptionalValue()) { if (queryMethod.isCollectionQuery() || queryMethod.isPageQuery() || queryMethod.isSliceQuery()) {
terminatingMethod = "one()"; terminatingMethod = "all()";
} else if (context.isCountMethod()) { } else if (count) {
terminatingMethod = "count()"; terminatingMethod = "count()";
} else if (context.isExistsMethod()) {
} else if (exists) {
terminatingMethod = "exists()"; terminatingMethod = "exists()";
} else { } else {
terminatingMethod = "oneValue()"; terminatingMethod = Optional.class.isAssignableFrom(context.getReturnType().toClass()) ? "one()" : "oneValue()";
}
} }
if (context.returnsPage()) { if (queryMethod.isPageQuery()) {
builder.addStatement("return new $T(finder, $L).execute($L)", PagedExecution.class, builder.addStatement("return new $T(finder, $L).execute($L)", PagedExecution.class,
context.getPageableParameterName(), queryVariableName); context.getPageableParameterName(), queryVariableName);
} else if (context.returnsSlice()) { } else if (queryMethod.isSliceQuery()) {
builder.addStatement("return new $T(finder, $L).execute($L)", SlicedExecution.class, builder.addStatement("return new $T(finder, $L).execute($L)", SlicedExecution.class,
context.getPageableParameterName(), queryVariableName); context.getPageableParameterName(), queryVariableName);
} else { } else {
@ -181,12 +200,14 @@ public class MongoBlocks {
static class QueryBlockBuilder { static class QueryBlockBuilder {
AotRepositoryMethodGenerationContext context; private final AotQueryMethodGenerationContext context;
private final MongoQueryMethod queryMethod;
StringQuery source; StringQuery source;
List<String> arguments; List<String> arguments;
private String queryVariableName; private String queryVariableName;
public QueryBlockBuilder(AotRepositoryMethodGenerationContext context) { public QueryBlockBuilder(AotQueryMethodGenerationContext context, MongoQueryMethod queryMethod) {
this.context = context; this.context = context;
this.arguments = Arrays.stream(context.getMethod().getParameters()).map(Parameter::getName) this.arguments = Arrays.stream(context.getMethod().getParameters()).map(Parameter::getName)
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -194,6 +215,7 @@ public class MongoBlocks {
// ParametersSource parametersSource = ParametersSource.of(repositoryInformation, metadata.getRepositoryMethod()); // ParametersSource parametersSource = ParametersSource.of(repositoryInformation, metadata.getRepositoryMethod());
// this.argumentSource = new MongoParameters(parametersSource, false); // this.argumentSource = new MongoParameters(parametersSource, false);
this.queryMethod = queryMethod;
} }
public QueryBlockBuilder filter(StringQuery query) { public QueryBlockBuilder filter(StringQuery query) {
@ -239,17 +261,20 @@ public class MongoBlocks {
} }
String pageableParameter = context.getPageableParameterName(); String pageableParameter = context.getPageableParameterName();
if (StringUtils.hasText(pageableParameter) && !context.returnsPage() && !context.returnsSlice()) { if (StringUtils.hasText(pageableParameter) && !queryMethod.isPageQuery() && !queryMethod.isSliceQuery()) {
builder.addStatement("$L.with($L)", queryVariableName, pageableParameter); builder.addStatement("$L.with($L)", queryVariableName, pageableParameter);
} }
String hint = context.annotationValue(Hint.class, "value"); MergedAnnotation<Hint> hintAnnotation = context.getAnnotation(Hint.class);
String hint = hintAnnotation.isPresent() ? hintAnnotation.getString("value") : null;
if (StringUtils.hasText(hint)) { if (StringUtils.hasText(hint)) {
builder.addStatement("$L.withHint($S)", queryVariableName, hint); builder.addStatement("$L.withHint($S)", queryVariableName, hint);
} }
String readPreference = context.annotationValue(ReadPreference.class, "value"); MergedAnnotation<ReadPreference> readPreferenceAnnotation = context.getAnnotation(ReadPreference.class);
String readPreference = readPreferenceAnnotation.isPresent() ? readPreferenceAnnotation.getString("value") : null;
if (StringUtils.hasText(readPreference)) { if (StringUtils.hasText(readPreference)) {
builder.addStatement("$L.withReadPreference($T.valueOf($S))", queryVariableName, builder.addStatement("$L.withReadPreference($T.valueOf($S))", queryVariableName,
com.mongodb.ReadPreference.class, readPreference); com.mongodb.ReadPreference.class, readPreference);

72
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/generated/MongoRepositoryContributor.java

@ -15,20 +15,27 @@
*/ */
package org.springframework.data.mongodb.aot.generated; package org.springframework.data.mongodb.aot.generated;
import java.lang.reflect.Method;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.jspecify.annotations.Nullable;
import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.data.mongodb.aot.generated.MongoBlocks.QueryBlockBuilder; import org.springframework.data.mongodb.aot.generated.MongoBlocks.QueryBlockBuilder;
import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.repository.Aggregation; import org.springframework.data.mongodb.repository.Aggregation;
import org.springframework.data.mongodb.repository.Query; import org.springframework.data.mongodb.repository.Query;
import org.springframework.data.mongodb.repository.query.MongoQueryMethod;
import org.springframework.data.repository.aot.generate.AotQueryMethodGenerationContext;
import org.springframework.data.repository.aot.generate.AotRepositoryConstructorBuilder; import org.springframework.data.repository.aot.generate.AotRepositoryConstructorBuilder;
import org.springframework.data.repository.aot.generate.AotRepositoryMethodBuilder; import org.springframework.data.repository.aot.generate.MethodContributor;
import org.springframework.data.repository.aot.generate.AotRepositoryMethodGenerationContext;
import org.springframework.data.repository.aot.generate.RepositoryContributor; import org.springframework.data.repository.aot.generate.RepositoryContributor;
import org.springframework.data.repository.config.AotRepositoryContext; import org.springframework.data.repository.config.AotRepositoryContext;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.query.parser.PartTree; import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.javapoet.MethodSpec.Builder; import org.springframework.javapoet.CodeBlock;
import org.springframework.javapoet.TypeName; import org.springframework.javapoet.TypeName;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -38,11 +45,13 @@ import org.springframework.util.StringUtils;
*/ */
public class MongoRepositoryContributor extends RepositoryContributor { public class MongoRepositoryContributor extends RepositoryContributor {
private AotQueryCreator queryCreator; private final AotQueryCreator queryCreator;
private final MongoMappingContext mappingContext;
public MongoRepositoryContributor(AotRepositoryContext repositoryContext) { public MongoRepositoryContributor(AotRepositoryContext repositoryContext) {
super(repositoryContext); super(repositoryContext);
this.queryCreator = new AotQueryCreator(); this.queryCreator = new AotQueryCreator();
this.mappingContext = new MongoMappingContext();
} }
@Override @Override
@ -51,36 +60,43 @@ public class MongoRepositoryContributor extends RepositoryContributor {
} }
@Override @Override
protected AotRepositoryMethodBuilder contributeRepositoryMethod( protected @Nullable MethodContributor<? extends QueryMethod> contributeQueryMethod(Method method,
AotRepositoryMethodGenerationContext generationContext) { RepositoryInformation repositoryInformation) {
// TODO: do not generate stuff for spel expressions
if (AnnotatedElementUtils.hasAnnotation(generationContext.getMethod(), Aggregation.class)) { if (AnnotatedElementUtils.hasAnnotation(method, Aggregation.class)) {
return null; return null;
} }
{
Query queryAnnotation = AnnotatedElementUtils.findMergedAnnotation(generationContext.getMethod(), Query.class); Query queryAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, Query.class);
if (queryAnnotation != null) { if (queryAnnotation != null) {
if (StringUtils.hasText(queryAnnotation.value()) if (StringUtils.hasText(queryAnnotation.value())
&& Pattern.compile("[\\?:][#$]\\{.*\\}").matcher(queryAnnotation.value()).find()) { && Pattern.compile("[\\?:][#$]\\{.*\\}").matcher(queryAnnotation.value()).find()) {
return null; return null;
} }
} }
}
// so the rest should work MongoQueryMethod queryMethod = new MongoQueryMethod(method, repositoryInformation, getProjectionFactory(),
return new AotRepositoryMethodBuilder(generationContext).customize((context, body) -> { mappingContext);
Query queryAnnotation = AnnotatedElementUtils.findMergedAnnotation(context.getMethod(), Query.class); return MethodContributor.forQueryMethod(queryMethod).contribute(context -> {
CodeBlock.Builder builder = CodeBlock.builder();
boolean count, delete, exists;
StringQuery query; StringQuery query;
if (queryAnnotation != null && StringUtils.hasText(queryAnnotation.value())) { if (queryAnnotation != null && StringUtils.hasText(queryAnnotation.value())) {
query = new StringQuery(queryAnnotation.value()); query = new StringQuery(queryAnnotation.value());
count = queryAnnotation.count();
delete = queryAnnotation.delete();
exists = queryAnnotation.exists();
} else { } else {
PartTree partTree = new PartTree(context.getMethod().getName(), PartTree partTree = new PartTree(context.getMethod().getName(),
context.getRepositoryInformation().getDomainType()); context.getRepositoryInformation().getDomainType());
query = queryCreator.createQuery(partTree, context.getMethod().getParameterCount()); query = queryCreator.createQuery(partTree, context.getMethod().getParameterCount());
count = partTree.isCountProjection();
delete = partTree.isDelete();
exists = partTree.isExistsProjection();
} }
if (queryAnnotation != null && StringUtils.hasText(queryAnnotation.sort())) { if (queryAnnotation != null && StringUtils.hasText(queryAnnotation.sort())) {
@ -90,29 +106,31 @@ public class MongoRepositoryContributor extends RepositoryContributor {
query.fields(queryAnnotation.fields()); query.fields(queryAnnotation.fields());
} }
writeStringQuery(context, body, query); writeStringQuery(context, builder, count, delete, exists, query, queryMethod);
return builder.build();
}); });
} }
private static void writeStringQuery(AotRepositoryMethodGenerationContext context, Builder body, StringQuery query) { private static void writeStringQuery(AotQueryMethodGenerationContext context, CodeBlock.Builder body, boolean count,
boolean delete, boolean exists, StringQuery query, MongoQueryMethod queryMethod) {
body.addCode(context.codeBlocks().logDebug("invoking [%s]".formatted(context.getMethod().getName()))); body.add(context.codeBlocks().logDebug("invoking [%s]".formatted(context.getMethod().getName())));
QueryBlockBuilder queryBlockBuilder = MongoBlocks.queryBlockBuilder(context).filter(query); QueryBlockBuilder queryBlockBuilder = MongoBlocks.queryBlockBuilder(context, queryMethod).filter(query);
if (context.isDeleteMethod()) { if (delete) {
String deleteQueryVariableName = "deleteQuery"; String deleteQueryVariableName = "deleteQuery";
body.addCode(queryBlockBuilder.usingQueryVariableName(deleteQueryVariableName).build()); body.add(queryBlockBuilder.usingQueryVariableName(deleteQueryVariableName).build());
body.addCode(MongoBlocks.deleteExecutionBlockBuilder(context).referencing(deleteQueryVariableName).build()); body.add(
MongoBlocks.deleteExecutionBlockBuilder(context, queryMethod).referencing(deleteQueryVariableName).build());
} else { } else {
String filterQueryVariableName = "filterQuery"; String filterQueryVariableName = "filterQuery";
body.addCode(queryBlockBuilder.usingQueryVariableName(filterQueryVariableName).build()); body.add(queryBlockBuilder.usingQueryVariableName(filterQueryVariableName).build());
body.addCode(MongoBlocks.queryExecutionBlockBuilder(context).referencing(filterQueryVariableName).build()); body.add(MongoBlocks.queryExecutionBlockBuilder(context, queryMethod).exists(exists).count(count)
.referencing(filterQueryVariableName).build());
} }
} }
private static void userAnnotatedQuery(AotRepositoryMethodGenerationContext context, Builder body, Query query) {
writeStringQuery(context, body, new StringQuery(query.value()));
}
} }

6
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java

@ -45,6 +45,7 @@ import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
import org.springframework.core.CollectionFactory; import org.springframework.core.CollectionFactory;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.convert.support.DefaultConversionService;
@ -2223,6 +2224,11 @@ public class MappingMongoConverter extends AbstractMongoConverter
public TypeDescriptor toTypeDescriptor() { public TypeDescriptor toTypeDescriptor() {
return delegate.toTypeDescriptor(); return delegate.toTypeDescriptor();
} }
@Override
public ResolvableType toResolvableType() {
return delegate.toResolvableType();
}
} }
/** /**

Loading…
Cancel
Save