Skip to content

Commit 40f2183

Browse files
just some stuff to see if it works the way we expect it to do
1 parent b046cb7 commit 40f2183

File tree

3 files changed

+195
-50
lines changed

3 files changed

+195
-50
lines changed
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.mongodb.aot.generated;
17+
18+
import java.lang.reflect.Parameter;
19+
import java.util.Arrays;
20+
import java.util.List;
21+
import java.util.stream.Collectors;
22+
23+
import org.springframework.data.mongodb.BindableMongoExpression;
24+
import org.springframework.data.mongodb.core.ExecutableFindOperation.TerminatingFind;
25+
import org.springframework.data.mongodb.core.MongoOperations;
26+
import org.springframework.data.mongodb.core.query.BasicQuery;
27+
import org.springframework.data.mongodb.repository.Hint;
28+
import org.springframework.data.mongodb.repository.ReadPreference;
29+
import org.springframework.data.repository.aot.generate.AotRepositoryMethodBuilder.MethodGenerationMetadata;
30+
import org.springframework.data.repository.core.RepositoryInformation;
31+
import org.springframework.data.support.PageableExecutionUtils;
32+
import org.springframework.javapoet.CodeBlock;
33+
import org.springframework.javapoet.CodeBlock.Builder;
34+
import org.springframework.javapoet.TypeName;
35+
import org.springframework.util.ObjectUtils;
36+
import org.springframework.util.StringUtils;
37+
38+
/**
39+
* @author Christoph Strobl
40+
*/
41+
public class MongoBlocks {
42+
43+
public static QueryBlockBuilder queryBlockBuilder(RepositoryInformation repositoryInformation,
44+
MethodGenerationMetadata metadata) {
45+
return new QueryBlockBuilder(repositoryInformation, metadata);
46+
}
47+
48+
public static QueryExecutionBlockBuilder queryExecutionBlockBuilder(RepositoryInformation repositoryInformation,
49+
MethodGenerationMetadata metadata) {
50+
return new QueryExecutionBlockBuilder(repositoryInformation, metadata);
51+
}
52+
53+
static class QueryExecutionBlockBuilder {
54+
55+
RepositoryInformation repositoryInformation;
56+
MethodGenerationMetadata metadata;
57+
58+
public QueryExecutionBlockBuilder(RepositoryInformation repositoryInformation, MethodGenerationMetadata metadata) {
59+
this.repositoryInformation = repositoryInformation;
60+
this.metadata = metadata;
61+
}
62+
63+
CodeBlock build(String queryVariableName) {
64+
65+
String mongoOpsRef = metadata.fieldNameOf(MongoOperations.class);
66+
67+
Builder builder = CodeBlock.builder();
68+
69+
boolean isProjecting = metadata.getActualReturnType() != null && !ObjectUtils
70+
.nullSafeEquals(TypeName.get(repositoryInformation.getDomainType()), metadata.getActualReturnType());
71+
Object actualReturnType = isProjecting ? metadata.getActualReturnType() : repositoryInformation.getDomainType();
72+
73+
if (isProjecting) {
74+
builder.addStatement("$T<$T> finder = $L.query($T.class).as($T.class).matching($L)", TerminatingFind.class,
75+
actualReturnType, mongoOpsRef, repositoryInformation.getDomainType(), actualReturnType, queryVariableName);
76+
} else {
77+
builder.addStatement("$T<$T> finder = $L.query($T.class).matching($L)", TerminatingFind.class, actualReturnType,
78+
mongoOpsRef, repositoryInformation.getDomainType(), queryVariableName);
79+
}
80+
81+
String terminatingMethod = "all()";
82+
if (metadata.returnsSingleValue()) {
83+
if (metadata.returnsOptionalValue()) {
84+
terminatingMethod = "one()";
85+
} else {
86+
terminatingMethod = "oneValue()";
87+
}
88+
}
89+
90+
if (!metadata.returnsPage()) {
91+
builder.addStatement("return finder.$L", terminatingMethod);
92+
} else {
93+
builder.addStatement("return $T.getPage(finder.$L, $L, () -> finder.count())", PageableExecutionUtils.class, terminatingMethod,
94+
metadata.getPageableParameterName());
95+
}
96+
97+
return builder.build();
98+
}
99+
100+
}
101+
102+
static class QueryBlockBuilder {
103+
104+
MethodGenerationMetadata metadata;
105+
String queryString;
106+
List<String> arguments;
107+
// MongoParameters argumentSource;
108+
109+
public QueryBlockBuilder(RepositoryInformation repositoryInformation, MethodGenerationMetadata metadata) {
110+
this.metadata = metadata;
111+
this.arguments = Arrays.stream(metadata.getRepositoryMethod().getParameters()).map(Parameter::getName)
112+
.collect(Collectors.toList());
113+
114+
// ParametersSource parametersSource = ParametersSource.of(repositoryInformation, metadata.getRepositoryMethod());
115+
// this.argumentSource = new MongoParameters(parametersSource, false);
116+
117+
}
118+
119+
public QueryBlockBuilder filter(String filter) {
120+
this.queryString = filter;
121+
return this;
122+
}
123+
124+
CodeBlock build(String queryVariableName) {
125+
126+
String mongoOpsRef = metadata.fieldNameOf(MongoOperations.class);
127+
128+
CodeBlock.Builder builder = CodeBlock.builder();
129+
130+
builder.addStatement("$T filter = new $T($S, $L.getConverter(), new $T[]{ $L })", BindableMongoExpression.class,
131+
BindableMongoExpression.class, queryString, mongoOpsRef, Object.class,
132+
StringUtils.collectionToCommaDelimitedString(arguments));
133+
builder.addStatement("$T $L = new $T(filter.toDocument())",
134+
org.springframework.data.mongodb.core.query.Query.class, queryVariableName, BasicQuery.class);
135+
136+
String sortParameter = metadata.getSortParameterName();
137+
if (StringUtils.hasText(sortParameter)) {
138+
builder.addStatement("$L.with($L)", queryVariableName, sortParameter);
139+
}
140+
141+
String limitParameter = metadata.getLimitParameterName();
142+
if (StringUtils.hasText(limitParameter)) {
143+
builder.addStatement("$L.limit($L)", queryVariableName, limitParameter);
144+
}
145+
146+
String pageableParameter = metadata.getPageableParameterName();
147+
if (StringUtils.hasText(pageableParameter)) {
148+
builder.addStatement("$L.with($L)", queryVariableName, pageableParameter);
149+
}
150+
151+
String hint = metadata.annotationValue(Hint.class, "value");
152+
153+
if (StringUtils.hasText(hint)) {
154+
builder.addStatement("$L.withHint($S)", queryVariableName, hint);
155+
}
156+
157+
String readPreference = metadata.annotationValue(ReadPreference.class, "value");
158+
if (StringUtils.hasText(readPreference)) {
159+
builder.addStatement("$L.withReadPreference($T.valueOf($S))", queryVariableName,
160+
com.mongodb.ReadPreference.class, readPreference);
161+
}
162+
163+
// TODO: all the meta stuff
164+
165+
return builder.build();
166+
}
167+
168+
}
169+
}

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

Lines changed: 13 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,10 @@
1515
*/
1616
package org.springframework.data.mongodb.aot.generated;
1717

18-
import java.lang.reflect.Parameter;
1918
import java.util.Arrays;
2019
import java.util.Iterator;
21-
import java.util.stream.Collectors;
2220
import java.util.stream.IntStream;
2321

24-
import org.apache.commons.logging.Log;
2522
import org.bson.conversions.Bson;
2623
import org.springframework.core.annotation.AnnotatedElementUtils;
2724
import org.springframework.data.domain.Pageable;
@@ -30,13 +27,11 @@
3027
import org.springframework.data.domain.Sort;
3128
import org.springframework.data.geo.Distance;
3229
import org.springframework.data.geo.Point;
33-
import org.springframework.data.mongodb.BindableMongoExpression;
3430
import org.springframework.data.mongodb.core.MongoOperations;
3531
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
3632
import org.springframework.data.mongodb.core.convert.MongoWriter;
3733
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
3834
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
39-
import org.springframework.data.mongodb.core.query.BasicQuery;
4035
import org.springframework.data.mongodb.core.query.Collation;
4136
import org.springframework.data.mongodb.core.query.CriteriaDefinition.Placeholder;
4237
import org.springframework.data.mongodb.core.query.TextCriteria;
@@ -49,6 +44,8 @@
4944
import org.springframework.data.repository.aot.generate.AotRepositoryConstructorBuilder;
5045
import org.springframework.data.repository.aot.generate.AotRepositoryMethodBuilder;
5146
import org.springframework.data.repository.aot.generate.AotRepositoryMethodBuilder.MethodGenerationMetadata;
47+
import org.springframework.data.repository.aot.generate.CodeBlocks;
48+
import org.springframework.data.repository.aot.generate.Contribution;
5249
import org.springframework.data.repository.aot.generate.RepositoryContributor;
5350
import org.springframework.data.repository.config.AotRepositoryContext;
5451
import org.springframework.data.repository.core.RepositoryInformation;
@@ -57,8 +54,6 @@
5754
import org.springframework.javapoet.MethodSpec.Builder;
5855
import org.springframework.javapoet.TypeName;
5956
import org.springframework.lang.Nullable;
60-
import org.springframework.util.ObjectUtils;
61-
import org.springframework.util.StringUtils;
6257

6358
import com.mongodb.DBRef;
6459

@@ -78,16 +73,14 @@ protected void customizeConstructor(AotRepositoryConstructorBuilder constructorB
7873
}
7974

8075
@Override
81-
protected void customizeDerivedMethod(AotRepositoryMethodBuilder methodBuilder) {
76+
protected Contribution customizeDerivedMethod(AotRepositoryMethodBuilder methodBuilder) {
8277

8378
methodBuilder.customize((repositoryInformation, metadata, body) -> {
8479
Query query = AnnotatedElementUtils.findMergedAnnotation(metadata.getRepositoryMethod(), Query.class);
8580
if (query != null) {
86-
userAnnotatedQuery(repositoryInformation, metadata, body, query);
81+
userAnnotatedQuery(repositoryInformation, metadata, methodBuilder.codeBlocks(), body, query);
8782
} else {
8883

89-
;
90-
9184
MongoMappingContext mongoMappingContext = new MongoMappingContext();
9285
mongoMappingContext.setSimpleTypeHolder(
9386
MongoCustomConversions.create((cfg) -> cfg.useNativeDriverJavaTimeCodecs()).getSimpleTypeHolder());
@@ -195,52 +188,22 @@ public Iterator<Object> iterator() {
195188
org.springframework.data.mongodb.core.query.Query partTreeQuery = queryCreator.createQuery();
196189
StringBuffer buffer = new StringBuffer();
197190
BsonUtils.writeJson(partTreeQuery.getQueryObject()).to(buffer);
198-
writeStringQuery(repositoryInformation, metadata, body, buffer.toString());
191+
writeStringQuery(repositoryInformation, metadata, methodBuilder.codeBlocks(), body, buffer.toString());
199192
}
200193
});
194+
return Contribution.CODE;
201195
}
202196

203197
private static void writeStringQuery(RepositoryInformation repositoryInformation, MethodGenerationMetadata metadata,
204-
Builder body, String query) {
205-
206-
String mongoOpsRef = metadata.fieldNameOf(MongoOperations.class);
207-
String arguments = StringUtils.collectionToCommaDelimitedString(Arrays
208-
.stream(metadata.getRepositoryMethod().getParameters()).map(Parameter::getName).collect(Collectors.toList()));
209-
210-
body.beginControlFlow("if($L.isDebugEnabled())", metadata.fieldNameOf(Log.class));
211-
body.addStatement("$L.debug(\"invoking generated [$L] method\")", metadata.fieldNameOf(Log.class),
212-
metadata.getRepositoryMethod().getName());
213-
body.endControlFlow();
214-
215-
body.addStatement("$T filter = new $T($S, $L.getConverter(), new $T[]{ $L })", BindableMongoExpression.class,
216-
BindableMongoExpression.class, query, mongoOpsRef, Object.class, arguments);
217-
body.addStatement("$T query = new $T(filter.toDocument())", org.springframework.data.mongodb.core.query.Query.class,
218-
BasicQuery.class);
219-
220-
boolean isCollectionType = TypeInformation.fromReturnTypeOf(metadata.getRepositoryMethod()).isCollectionLike();
221-
String terminatingMethod = isCollectionType ? "all()" : "oneValue()";
222-
223-
if (metadata.getActualReturnType() != null && ObjectUtils
224-
.nullSafeEquals(TypeName.get(repositoryInformation.getDomainType()), metadata.getActualReturnType())) {
225-
body.addStatement("""
226-
return $L.query($T.class)
227-
.matching(query)
228-
.$L""", mongoOpsRef, repositoryInformation.getDomainType(), terminatingMethod);
229-
} else {
230-
231-
body.addStatement("""
232-
return $L.query($T.class)
233-
.as($T.class)
234-
.matching(query)
235-
.$L""", mongoOpsRef, repositoryInformation.getDomainType(),
236-
metadata.getActualReturnType() != null ? metadata.getActualReturnType()
237-
: repositoryInformation.getDomainType(),
238-
terminatingMethod);
239-
}
198+
CodeBlocks codeBlocks, Builder body, String query) {
199+
200+
body.addCode(codeBlocks.logDebug("invoking [%s]".formatted(metadata.getRepositoryMethod().getName())));
201+
body.addCode(MongoBlocks.queryBlockBuilder(repositoryInformation, metadata).filter(query).build("query"));
202+
body.addCode(MongoBlocks.queryExecutionBlockBuilder(repositoryInformation, metadata).build("query"));
240203
}
241204

242205
private static void userAnnotatedQuery(RepositoryInformation repositoryInformation, MethodGenerationMetadata metadata,
243-
Builder body, Query query) {
244-
writeStringQuery(repositoryInformation, metadata, body, query.value());
206+
CodeBlocks codeBlocks, Builder body, Query query) {
207+
writeStringQuery(repositoryInformation, metadata, codeBlocks, body, query.value());
245208
}
246209
}

spring-data-mongodb/src/test/java/example/aot/UserRepository.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717

1818
import java.util.List;
1919

20+
import org.springframework.data.domain.Limit;
21+
import org.springframework.data.domain.Page;
22+
import org.springframework.data.domain.Pageable;
23+
import org.springframework.data.domain.Sort;
2024
import org.springframework.data.mongodb.repository.Query;
25+
import org.springframework.data.mongodb.repository.ReadPreference;
2126
import org.springframework.data.repository.CrudRepository;
2227

2328
/**
@@ -30,7 +35,15 @@ public interface UserRepository extends CrudRepository<User, String> {
3035
@Query("{ 'username' : '?0' }")
3136
List<User> findAllByAnnotatedQueryWithParameter(String username);
3237

38+
@ReadPreference("secondary")
3339
User findByUsername(String username);
3440

3541
List<User> findUserByLastnameLike(String lastname);
42+
43+
List<User> findUserByLastnameStartingWith(String lastname, Pageable page);
44+
List<User> findUserByLastnameStartingWith(String lastname, Sort sort);
45+
List<User> findUserByLastnameStartingWith(String lastname, Limit limit);
46+
List<User> findUserByLastnameStartingWith(String lastname, Sort sort, Limit limit);
47+
48+
Page<User> findUserByFirstnameStartingWith(String lastname, Pageable page);
3649
}

0 commit comments

Comments
 (0)