Skip to content

Commit 61c9cbc

Browse files
committed
Retain active profiles used during AOT processing
This commit makes sure that profiles that have been explicitly enabled during AOT optimizations are automatically enabled when using those optimizations. If other profiles are set at runtime, they take precedence over the ones defined during AOT processing. Closes gh-30421
1 parent 446b901 commit 61c9cbc

File tree

3 files changed

+58
-6
lines changed

3 files changed

+58
-6
lines changed

spring-context/src/main/java/org/springframework/context/aot/ApplicationContextAotGenerator.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -52,9 +52,9 @@ public ClassName processAheadOfTime(GenericApplicationContext applicationContext
5252
GenerationContext generationContext) {
5353
return withCglibClassHandler(new CglibClassHandler(generationContext), () -> {
5454
applicationContext.refreshForAotProcessing(generationContext.getRuntimeHints());
55-
DefaultListableBeanFactory beanFactory = applicationContext.getDefaultListableBeanFactory();
5655
ApplicationContextInitializationCodeGenerator codeGenerator =
57-
new ApplicationContextInitializationCodeGenerator(generationContext);
56+
new ApplicationContextInitializationCodeGenerator(applicationContext, generationContext);
57+
DefaultListableBeanFactory beanFactory = applicationContext.getDefaultListableBeanFactory();
5858
new BeanFactoryInitializationAotContributions(beanFactory).applyTo(generationContext, codeGenerator);
5959
return codeGenerator.getGeneratedClass().getName();
6060
});

spring-context/src/main/java/org/springframework/context/aot/ApplicationContextInitializationCodeGenerator.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.context.aot;
1818

1919
import java.util.ArrayList;
20+
import java.util.Arrays;
2021
import java.util.List;
2122
import java.util.function.Function;
2223

@@ -49,6 +50,7 @@
4950
* Internal code generator to create the {@link ApplicationContextInitializer}.
5051
*
5152
* @author Phillip Webb
53+
* @author Stephane Nicoll
5254
* @since 6.0
5355
*/
5456
class ApplicationContextInitializationCodeGenerator implements BeanFactoryInitializationCode {
@@ -57,12 +59,15 @@ class ApplicationContextInitializationCodeGenerator implements BeanFactoryInitia
5759

5860
private static final String APPLICATION_CONTEXT_VARIABLE = "applicationContext";
5961

60-
private final List<MethodReference> initializers = new ArrayList<>();
62+
private final GenericApplicationContext applicationContext;
6163

6264
private final GeneratedClass generatedClass;
6365

66+
private final List<MethodReference> initializers = new ArrayList<>();
67+
6468

65-
ApplicationContextInitializationCodeGenerator(GenerationContext generationContext) {
69+
ApplicationContextInitializationCodeGenerator(GenericApplicationContext applicationContext, GenerationContext generationContext) {
70+
this.applicationContext = applicationContext;
6671
this.generatedClass = generationContext.getGeneratedClasses()
6772
.addForFeature("ApplicationContextInitializer", this::generateType);
6873
this.generatedClass.reserveMethodNames(INITIALIZE_METHOD);
@@ -97,13 +102,25 @@ private CodeBlock generateInitializeCode() {
97102
BEAN_FACTORY_VARIABLE, ContextAnnotationAutowireCandidateResolver.class);
98103
code.addStatement("$L.setDependencyComparator($T.INSTANCE)",
99104
BEAN_FACTORY_VARIABLE, AnnotationAwareOrderComparator.class);
105+
code.add(generateActiveProfilesInitializeCode());
100106
ArgumentCodeGenerator argCodeGenerator = createInitializerMethodArgumentCodeGenerator();
101107
for (MethodReference initializer : this.initializers) {
102108
code.addStatement(initializer.toInvokeCodeBlock(argCodeGenerator, this.generatedClass.getName()));
103109
}
104110
return code.build();
105111
}
106112

113+
private CodeBlock generateActiveProfilesInitializeCode() {
114+
CodeBlock.Builder code = CodeBlock.builder();
115+
ConfigurableEnvironment environment = this.applicationContext.getEnvironment();
116+
if (!Arrays.equals(environment.getActiveProfiles(), environment.getDefaultProfiles())) {
117+
for (String activeProfile : environment.getActiveProfiles()) {
118+
code.addStatement("$L.getEnvironment().addActiveProfile($S)", APPLICATION_CONTEXT_VARIABLE, activeProfile);
119+
}
120+
}
121+
return code.build();
122+
}
123+
107124
static ArgumentCodeGenerator createInitializerMethodArgumentCodeGenerator() {
108125
return ArgumentCodeGenerator.from(new InitializerMethodArgumentCodeGenerator());
109126
}

spring-context/src/test/java/org/springframework/context/aot/ApplicationContextAotGeneratorTests.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,13 @@
2222
import java.util.List;
2323
import java.util.function.BiConsumer;
2424
import java.util.function.Consumer;
25+
import java.util.stream.Stream;
2526

2627
import org.junit.jupiter.api.Nested;
2728
import org.junit.jupiter.api.Test;
29+
import org.junit.jupiter.params.ParameterizedTest;
30+
import org.junit.jupiter.params.provider.Arguments;
31+
import org.junit.jupiter.params.provider.MethodSource;
2832

2933
import org.springframework.aot.generate.GeneratedFiles.Kind;
3034
import org.springframework.aot.generate.GenerationContext;
@@ -384,6 +388,37 @@ void processAheadOfTimeWhenHasCglibProxyWithArgumentsRegisterIntrospectionHintsO
384388

385389
}
386390

391+
@Nested
392+
static class ActiveProfile {
393+
394+
@ParameterizedTest
395+
@MethodSource("activeProfilesParameters")
396+
void processAheadOfTimeWhenHasActiveProfiles(String[] aotProfiles, String[] runtimeProfiles, String[] expectedActiveProfiles) {
397+
GenericApplicationContext applicationContext = new GenericApplicationContext();
398+
if (aotProfiles.length != 0) {
399+
applicationContext.getEnvironment().setActiveProfiles(aotProfiles);
400+
}
401+
testCompiledResult(applicationContext, (initializer, compiled) -> {
402+
GenericApplicationContext freshApplicationContext = new GenericApplicationContext();
403+
if (runtimeProfiles.length != 0) {
404+
freshApplicationContext.getEnvironment().setActiveProfiles(runtimeProfiles);
405+
}
406+
initializer.initialize(freshApplicationContext);
407+
freshApplicationContext.refresh();
408+
assertThat(freshApplicationContext.getEnvironment().getActiveProfiles()).containsExactly(expectedActiveProfiles);
409+
});
410+
}
411+
412+
static Stream<Arguments> activeProfilesParameters() {
413+
return Stream.of(Arguments.of(new String[] { "aot", "prod" }, new String[] {}, new String[] { "aot", "prod" }),
414+
Arguments.of(new String[] {}, new String[] { "aot", "prod" }, new String[] { "aot", "prod" }),
415+
Arguments.of(new String[] { "aot" }, new String[] { "prod" }, new String[] { "prod", "aot" }),
416+
Arguments.of(new String[] { "aot", "prod" }, new String[] { "aot", "prod" }, new String[] { "aot", "prod" }),
417+
Arguments.of(new String[] { "default" }, new String[] {}, new String[] {}));
418+
}
419+
420+
}
421+
387422
private Consumer<List<? extends JdkProxyHint>> doesNotHaveProxyFor(Class<?> target) {
388423
return hints -> assertThat(hints).noneMatch(hint ->
389424
hint.getProxiedInterfaces().get(0).equals(TypeReference.of(target)));

0 commit comments

Comments
 (0)