Skip to content

Commit e78a3ab

Browse files
Use explicitly configured MongoOperations for AOT fragment bootstrap.
This commit makes sure to use a configured MongoOperations reference to bootstrap AOT generated repository implementations. Previously mongoTemplateRef set via EnableMongoRepositories had not been taken into account.
1 parent fb3dc9a commit e78a3ab

File tree

2 files changed

+110
-5
lines changed

2 files changed

+110
-5
lines changed

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

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import org.apache.commons.logging.Log;
2626
import org.apache.commons.logging.LogFactory;
2727
import org.jspecify.annotations.Nullable;
28-
28+
import org.springframework.beans.factory.config.RuntimeBeanReference;
2929
import org.springframework.core.annotation.AnnotatedElementUtils;
3030
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
3131
import org.springframework.data.mapping.model.SimpleTypeHolder;
@@ -72,6 +72,7 @@ public class MongoRepositoryContributor extends RepositoryContributor {
7272
private final SimpleTypeHolder simpleTypeHolder;
7373
private final MongoMappingContext mappingContext;
7474
private final NamedQueries namedQueries;
75+
private final @Nullable String mongoOperationsRef;
7576

7677
public MongoRepositoryContributor(AotRepositoryContext repositoryContext) {
7778

@@ -81,7 +82,9 @@ public MongoRepositoryContributor(AotRepositoryContext repositoryContext) {
8182
if (classLoader == null) {
8283
classLoader = getClass().getClassLoader();
8384
}
84-
namedQueries = getNamedQueries(repositoryContext.getConfigurationSource(), classLoader);
85+
86+
this.namedQueries = getNamedQueries(repositoryContext.getConfigurationSource(), classLoader);
87+
this.mongoOperationsRef = getMongoTemplateRef(repositoryContext.getConfigurationSource());
8588

8689
// avoid Java Time (JSR-310) Type introspection
8790
MongoCustomConversions mongoCustomConversions = MongoCustomConversions
@@ -97,6 +100,14 @@ public MongoRepositoryContributor(AotRepositoryContext repositoryContext) {
97100
this.queryCreator = new AotQueryCreator(this.mappingContext);
98101
}
99102

103+
private @Nullable String getMongoTemplateRef(@Nullable RepositoryConfigurationSource configSource) {
104+
if (configSource == null) {
105+
return null;
106+
}
107+
108+
return configSource.getAttribute("mongoTemplateRef").filter(it -> !"mongoTemplate".equals(it)).orElse(null);
109+
}
110+
100111
@SuppressWarnings("NullAway")
101112
private NamedQueries getNamedQueries(@Nullable RepositoryConfigurationSource configSource, ClassLoader classLoader) {
102113

@@ -132,9 +143,15 @@ protected void customizeClass(AotRepositoryClassBuilder classBuilder) {
132143
@Override
133144
protected void customizeConstructor(AotRepositoryConstructorBuilder constructorBuilder) {
134145

135-
constructorBuilder.addParameter("operations", MongoOperations.class);
136-
constructorBuilder.addParameter("context", RepositoryFactoryBeanSupport.FragmentCreationContext.class,
137-
false);
146+
constructorBuilder.addParameter("operations", MongoOperations.class, customizer -> {
147+
148+
customizer.bindToField()
149+
.origin(StringUtils.hasText(this.mongoOperationsRef)
150+
? new RuntimeBeanReference(this.mongoOperationsRef, MongoOperations.class)
151+
: new RuntimeBeanReference(MongoOperations.class));
152+
});
153+
154+
constructorBuilder.addParameter("context", RepositoryFactoryBeanSupport.FragmentCreationContext.class, false);
138155

139156
constructorBuilder.customize((builder) -> {
140157
builder.addStatement("super(operations, context)");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2025-present 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.repository.aot;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
20+
import java.io.IOException;
21+
import java.nio.charset.StandardCharsets;
22+
23+
import org.junit.jupiter.api.Test;
24+
import org.springframework.aot.generate.GeneratedFiles.Kind;
25+
import org.springframework.aot.test.generate.TestGenerationContext;
26+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
27+
import org.springframework.context.annotation.Configuration;
28+
import org.springframework.context.aot.ApplicationContextAotGenerator;
29+
import org.springframework.core.io.InputStreamResource;
30+
import org.springframework.core.io.InputStreamSource;
31+
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
32+
33+
/**
34+
* @author Christoph Strobl
35+
*/
36+
class MongoRepositoryContributorConfigurationTests {
37+
38+
@Configuration
39+
@EnableMongoRepositories(basePackages = "example.aot")
40+
static class ConfigurationWithoutAnythingSpecial {
41+
42+
}
43+
44+
@Configuration
45+
@EnableMongoRepositories(mongoTemplateRef = "template-2", basePackages = "example.aot")
46+
static class ConfigurationWithTemplateRef {
47+
48+
}
49+
50+
@Test // GH-5107
51+
void usesPrimaryMongoOperationsBeanReferenceByDefault() throws IOException {
52+
53+
TestGenerationContext testContext = generate(ConfigurationWithoutAnythingSpecial.class);
54+
InputStreamSource file = testContext.getGeneratedFiles().getGeneratedFile(Kind.SOURCE,
55+
"example/aot/UserRepository__BeanDefinitions.java");
56+
57+
InputStreamResource isr = new InputStreamResource(file);
58+
String sourceCode = isr.getContentAsString(StandardCharsets.UTF_8);
59+
60+
assertThat(sourceCode).contains("operations = beanFactory.getBean(MongoOperations.class)");
61+
}
62+
63+
@Test // GH-5107
64+
void shouldConsiderMongoTemplateReferenceIfPresent() throws IOException {
65+
66+
TestGenerationContext testContext = generate(ConfigurationWithTemplateRef.class);
67+
InputStreamSource file = testContext.getGeneratedFiles().getGeneratedFile(Kind.SOURCE,
68+
"example/aot/UserRepository__BeanDefinitions.java");
69+
70+
InputStreamResource isr = new InputStreamResource(file);
71+
String sourceCode = isr.getContentAsString(StandardCharsets.UTF_8);
72+
73+
assertThat(sourceCode).contains("operations = beanFactory.getBean(\"template-2\", MongoOperations.class)");
74+
}
75+
76+
private static TestGenerationContext generate(Class<?>... configurationClasses) {
77+
78+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
79+
context.register(configurationClasses);
80+
81+
ApplicationContextAotGenerator generator = new ApplicationContextAotGenerator();
82+
83+
TestGenerationContext generationContext = new TestGenerationContext();
84+
generator.processAheadOfTime(context, generationContext);
85+
generationContext.writeGeneratedContent();
86+
return generationContext;
87+
}
88+
}

0 commit comments

Comments
 (0)