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. 99
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/aot/generated/MongoBlocks.java
  2. 80
      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

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

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

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

Loading…
Cancel
Save