Skip to content

Commit 61cbfb5

Browse files
committed
Polishing.
Introduce constants and test. Update documentation. Original pull request: #5017 See #4983
1 parent 8a9e6bf commit 61cbfb5

File tree

3 files changed

+219
-5
lines changed

3 files changed

+219
-5
lines changed

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,31 @@
1616
package org.springframework.data.mongodb.repository.aot;
1717

1818
import org.jspecify.annotations.Nullable;
19+
1920
import org.springframework.aot.generate.GenerationContext;
20-
import org.springframework.data.aot.AotContext;
2121
import org.springframework.data.mongodb.aot.LazyLoadingProxyAotProcessor;
2222
import org.springframework.data.mongodb.aot.MongoAotPredicates;
23-
import org.springframework.data.repository.aot.generate.RepositoryContributor;
2423
import org.springframework.data.repository.config.AotRepositoryContext;
2524
import org.springframework.data.repository.config.RepositoryRegistrationAotProcessor;
2625
import org.springframework.data.util.TypeContributor;
2726
import org.springframework.data.util.TypeUtils;
2827

2928
/**
29+
* Mongodb-specific {@link RepositoryRegistrationAotProcessor} that contributes generated code for repositories.
30+
*
3031
* @author Christoph Strobl
32+
* @since 4.0
3133
*/
3234
public class AotMongoRepositoryPostProcessor extends RepositoryRegistrationAotProcessor {
3335

36+
private static final String MODULE_NAME = "mongodb";
37+
3438
private final LazyLoadingProxyAotProcessor lazyLoadingProxyAotProcessor = new LazyLoadingProxyAotProcessor();
3539

3640
@Override
37-
protected @Nullable RepositoryContributor contribute(AotRepositoryContext repositoryContext,
41+
protected @Nullable MongoRepositoryContributor contribute(AotRepositoryContext repositoryContext,
3842
GenerationContext generationContext) {
43+
3944
// do some custom type registration here
4045
super.contribute(repositoryContext, generationContext);
4146

@@ -44,7 +49,7 @@ public class AotMongoRepositoryPostProcessor extends RepositoryRegistrationAotPr
4449
lazyLoadingProxyAotProcessor.registerLazyLoadingProxyIfNeeded(type, generationContext);
4550
});
4651

47-
if (!repositoryContext.isGeneratedRepositoriesEnabled("mongodb")) {
52+
if (!repositoryContext.isGeneratedRepositoriesEnabled(MODULE_NAME)) {
4853
return null;
4954
}
5055

@@ -57,6 +62,8 @@ protected void contributeType(Class<?> type, GenerationContext generationContext
5762
if (TypeUtils.type(type).isPartOf("org.springframework.data.mongodb", "com.mongodb")) {
5863
return;
5964
}
65+
6066
super.contributeType(type, generationContext);
6167
}
68+
6269
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
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.repository.aot;
17+
18+
import static org.assertj.core.api.Assertions.*;
19+
import static org.mockito.Mockito.*;
20+
21+
import java.lang.annotation.Annotation;
22+
import java.util.Collections;
23+
import java.util.List;
24+
import java.util.Set;
25+
26+
import org.jmolecules.ddd.annotation.Entity;
27+
import org.jspecify.annotations.Nullable;
28+
import org.junit.jupiter.api.Test;
29+
import org.junitpioneer.jupiter.ClearSystemProperty;
30+
import org.junitpioneer.jupiter.SetSystemProperty;
31+
32+
import org.springframework.aot.AotDetector;
33+
import org.springframework.aot.generate.ClassNameGenerator;
34+
import org.springframework.aot.generate.DefaultGenerationContext;
35+
import org.springframework.aot.generate.GenerationContext;
36+
import org.springframework.aot.generate.InMemoryGeneratedFiles;
37+
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
38+
import org.springframework.context.support.AbstractApplicationContext;
39+
import org.springframework.context.support.GenericApplicationContext;
40+
import org.springframework.core.annotation.MergedAnnotation;
41+
import org.springframework.core.env.Environment;
42+
import org.springframework.core.env.StandardEnvironment;
43+
import org.springframework.data.annotation.Id;
44+
import org.springframework.data.aot.AotContext;
45+
import org.springframework.data.mongodb.repository.support.SimpleMongoRepository;
46+
import org.springframework.data.repository.Repository;
47+
import org.springframework.data.repository.config.AotRepositoryContext;
48+
import org.springframework.data.repository.config.AotRepositoryInformation;
49+
import org.springframework.data.repository.config.RepositoryConfigurationSource;
50+
import org.springframework.data.repository.core.RepositoryInformation;
51+
import org.springframework.data.repository.core.support.AbstractRepositoryMetadata;
52+
import org.springframework.javapoet.ClassName;
53+
54+
/**
55+
* Unit tests for {@link AotMongoRepositoryPostProcessor}.
56+
*
57+
* @author Mark Paluch
58+
*/
59+
class AotMongoRepositoryPostProcessorUnitTests {
60+
61+
@Test // GH-4893
62+
@SetSystemProperty(key = AotDetector.AOT_ENABLED, value = "true")
63+
void repositoryProcessorShouldEnableAotRepositoriesByDefaultWhenAotIsEnabled() {
64+
65+
GenerationContext ctx = createGenerationContext();
66+
GenericApplicationContext context = new GenericApplicationContext();
67+
68+
MongoRepositoryContributor contributor = createContributorWithPersonTypes(context, ctx);
69+
70+
assertThat(contributor).isNotNull();
71+
}
72+
73+
@Test // GH-4893
74+
@ClearSystemProperty(key = AotContext.GENERATED_REPOSITORIES_ENABLED)
75+
void shouldEnableAotRepositoriesByDefault() {
76+
77+
GenerationContext ctx = createGenerationContext();
78+
GenericApplicationContext context = new GenericApplicationContext();
79+
80+
MongoRepositoryContributor contributor = createContributorWithPersonTypes(context, ctx);
81+
82+
assertThat(contributor).isNotNull();
83+
}
84+
85+
@Test // GH-4893
86+
@SetSystemProperty(key = AotContext.GENERATED_REPOSITORIES_ENABLED, value = "false")
87+
void shouldDisableAotRepositoriesWhenGeneratedRepositoriesIsFalse() {
88+
89+
GenerationContext ctx = createGenerationContext();
90+
GenericApplicationContext context = new GenericApplicationContext();
91+
92+
MongoRepositoryContributor contributor = createContributorWithPersonTypes(context, ctx);
93+
94+
assertThat(contributor).isNull();
95+
}
96+
97+
@Test // GH-3899
98+
@SetSystemProperty(key = "spring.aot.mongodb.repositories.enabled", value = "false")
99+
void shouldDisableAotRepositoriesWhenJpaGeneratedRepositoriesIsFalse() {
100+
101+
GenerationContext ctx = createGenerationContext();
102+
GenericApplicationContext context = new GenericApplicationContext();
103+
104+
MongoRepositoryContributor contributor = createContributorWithPersonTypes(context, ctx);
105+
106+
assertThat(contributor).isNull();
107+
}
108+
109+
private GenerationContext createGenerationContext() {
110+
return new DefaultGenerationContext(new ClassNameGenerator(ClassName.OBJECT), new InMemoryGeneratedFiles());
111+
}
112+
113+
private MongoRepositoryContributor createContributorWithPersonTypes(GenericApplicationContext context,
114+
GenerationContext ctx) {
115+
116+
return new AotMongoRepositoryPostProcessor().contribute(new DummyAotRepositoryContext(context) {
117+
@Override
118+
public Set<Class<?>> getResolvedTypes() {
119+
return Collections.singleton(Person.class);
120+
}
121+
}, ctx);
122+
}
123+
124+
@Entity
125+
static class Person {
126+
@Id Long id;
127+
}
128+
129+
interface PersonRepository extends Repository<Person, Long> {}
130+
131+
static class DummyAotRepositoryContext implements AotRepositoryContext {
132+
133+
private final @Nullable AbstractApplicationContext applicationContext;
134+
135+
DummyAotRepositoryContext(@Nullable AbstractApplicationContext applicationContext) {
136+
this.applicationContext = applicationContext;
137+
}
138+
139+
@Override
140+
public String getBeanName() {
141+
return "jpaRepository";
142+
}
143+
144+
@Override
145+
public String getModuleName() {
146+
return "JPA";
147+
}
148+
149+
@Override
150+
public RepositoryConfigurationSource getConfigurationSource() {
151+
return mock(RepositoryConfigurationSource.class);
152+
}
153+
154+
@Override
155+
public Set<String> getBasePackages() {
156+
return Collections.singleton(this.getClass().getPackageName());
157+
}
158+
159+
@Override
160+
public Set<Class<? extends Annotation>> getIdentifyingAnnotations() {
161+
return Collections.singleton(Entity.class);
162+
}
163+
164+
@Override
165+
public RepositoryInformation getRepositoryInformation() {
166+
return new AotRepositoryInformation(AbstractRepositoryMetadata.getMetadata(PersonRepository.class),
167+
SimpleMongoRepository.class, List.of());
168+
}
169+
170+
@Override
171+
public Set<MergedAnnotation<Annotation>> getResolvedAnnotations() {
172+
return Set.of();
173+
}
174+
175+
@Override
176+
public Set<Class<?>> getResolvedTypes() {
177+
return Set.of();
178+
}
179+
180+
@Override
181+
public ConfigurableListableBeanFactory getBeanFactory() {
182+
return applicationContext != null ? applicationContext.getBeanFactory() : null;
183+
}
184+
185+
@Override
186+
public Environment getEnvironment() {
187+
return applicationContext == null ? new StandardEnvironment() : applicationContext.getEnvironment();
188+
}
189+
190+
@Override
191+
public TypeIntrospector introspectType(String typeName) {
192+
return null;
193+
}
194+
195+
@Override
196+
public IntrospectedBeanDefinition introspectBeanDefinition(String beanName) {
197+
return null;
198+
}
199+
200+
}
201+
202+
}

src/main/antora/modules/ROOT/pages/mongodb/aot.adoc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,12 @@ Do not use them directly in your code as generation and implementation details m
4343
=== Running with AOT Repositories
4444

4545
AOT is a mandatory step to transform a Spring application to a native executable, so it is automatically enabled when running in this mode.
46-
It is also possible to use those optimizations on the JVM by setting the `spring.aot.enabled` and `spring.aot.repositories.enabled` System properties to `true`.
46+
When AOT is enabled (either for native compilation or by setting `spring.aot.enabled=true`), AOT repositories are automatically enabled by default.
47+
48+
You can disable AOT repository generation entirely or only disable MongoDB AOT repositories:
49+
50+
* Set the `spring.aot.repositories.enabled=false` property to disable generated repositories for all Spring Data modules.
51+
* Set the `spring.aot.mongodb.repositories.enabled=false` property to disable only MongoDB AOT repositories.
4752

4853
AOT repositories contribute configuration changes to the actual repository bean registration to register the generated repository fragment.
4954

0 commit comments

Comments
 (0)