Skip to content

Commit 8cf63a2

Browse files
committed
Update AOT work to latest Framework code
1 parent 88250f9 commit 8cf63a2

File tree

5 files changed

+72
-42
lines changed

5 files changed

+72
-42
lines changed

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/GenerateAotSources.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public class GenerateAotSources extends JavaExec {
4242

4343
private final DirectoryProperty resourcesDir;
4444

45+
private final DirectoryProperty classesDir;
46+
4547
private final Property<String> groupId;
4648

4749
private final Property<String> artifactId;
@@ -50,6 +52,7 @@ public GenerateAotSources() {
5052
this.applicationClass = getProject().getObjects().property(String.class);
5153
this.sourcesDir = getProject().getObjects().directoryProperty();
5254
this.resourcesDir = getProject().getObjects().directoryProperty();
55+
this.classesDir = getProject().getObjects().directoryProperty();
5356
this.groupId = getProject().getObjects().property(String.class);
5457
this.artifactId = getProject().getObjects().property(String.class);
5558
getMainClass().set("org.springframework.boot.AotProcessor");
@@ -80,13 +83,19 @@ public DirectoryProperty getResourcesDir() {
8083
return this.resourcesDir;
8184
}
8285

86+
@OutputDirectory
87+
public DirectoryProperty getClassesDir() {
88+
return this.classesDir;
89+
}
90+
8391
@Override
8492
@TaskAction
8593
public void exec() {
8694
List<String> args = new ArrayList<>();
8795
args.add(this.applicationClass.get());
8896
args.add(this.sourcesDir.getAsFile().get().getAbsolutePath());
8997
args.add(this.resourcesDir.getAsFile().get().getAbsolutePath());
98+
args.add(this.classesDir.getAsFile().get().getAbsolutePath());
9099
args.addAll(super.getArgs());
91100
this.setArgs(args);
92101
super.exec();

spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/AotGenerateTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ void whenAotRunsSourcesAreGenerated(MavenBuild mavenBuild) {
3939
mavenBuild.project("aot").goals("package").execute((project) -> {
4040
Path aotDirectory = project.toPath().resolve("target/spring-aot/main");
4141
assertThat(collectRelativeFileNames(aotDirectory.resolve("sources")))
42-
.containsOnly("org/test/SampleApplication__ApplicationContextInitializer.java");
42+
.contains("org/test/SampleApplication__ApplicationContextInitializer.java");
4343
assertThat(collectRelativeFileNames(aotDirectory.resolve("resources"))).containsOnly(
4444
"META-INF/native-image/org.springframework.boot.maven.it/aot/reflect-config.json",
4545
"META-INF/native-image/org.springframework.boot.maven.it/aot/native-image.properties");

spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AotGenerateMojo.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ public class AotGenerateMojo extends AbstractRunMojo {
7373
@Parameter(defaultValue = "${project.build.directory}/spring-aot/main/resources", required = true)
7474
private File generatedResources;
7575

76+
/**
77+
* Directory containing the generated classes.
78+
*/
79+
@Parameter(defaultValue = "${project.build.directory}/spring-aot/main/classes", required = true)
80+
private File generatedClasses;
81+
7682
@Override
7783
protected void run(File workingDirectory, String startClassName, Map<String, String> environmentVariables)
7884
throws MojoExecutionException, MojoFailureException {
@@ -90,6 +96,7 @@ protected void run(File workingDirectory, String startClassName, Map<String, Str
9096
private void deletePreviousAotAssets() {
9197
FileSystemUtils.deleteRecursively(this.generatedSources);
9298
FileSystemUtils.deleteRecursively(this.generatedResources);
99+
FileSystemUtils.deleteRecursively(this.generatedClasses);
93100
}
94101

95102
private void generateAotAssets(File workingDirectory, String startClassName,
@@ -102,6 +109,7 @@ private void generateAotAssets(File workingDirectory, String startClassName,
102109
args.add(startClassName);
103110
args.add(this.generatedSources.toString());
104111
args.add(this.generatedResources.toString());
112+
args.add(this.generatedClasses.toString());
105113
args.add(this.project.getGroupId());
106114
args.add(this.project.getArtifactId());
107115
addArgs(args);

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/AotProcessor.java

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,19 @@
2424
import java.util.Arrays;
2525
import java.util.Collections;
2626
import java.util.List;
27+
import java.util.function.Consumer;
2728

28-
import org.springframework.aot.generator.DefaultGeneratedTypeContext;
29-
import org.springframework.aot.generator.GeneratedType;
30-
import org.springframework.aot.generator.GeneratedTypeReference;
29+
import org.springframework.aot.generate.DefaultGenerationContext;
30+
import org.springframework.aot.generate.FileSystemGeneratedFiles;
31+
import org.springframework.aot.generate.GeneratedFiles.Kind;
32+
import org.springframework.aot.hint.ExecutableHint;
3133
import org.springframework.aot.hint.ExecutableMode;
3234
import org.springframework.aot.hint.RuntimeHints;
3335
import org.springframework.aot.hint.TypeReference;
3436
import org.springframework.aot.nativex.FileNativeConfigurationWriter;
35-
import org.springframework.context.generator.ApplicationContextAotGenerator;
37+
import org.springframework.context.aot.ApplicationContextAotGenerator;
3638
import org.springframework.context.support.GenericApplicationContext;
3739
import org.springframework.javapoet.ClassName;
38-
import org.springframework.javapoet.JavaFile;
3940
import org.springframework.util.Assert;
4041

4142
/**
@@ -45,10 +46,14 @@
4546
*
4647
* @author Stephane Nicoll
4748
* @author Andy Wilkinson
49+
* @author Phillip Webb
4850
* @since 3.0
4951
*/
5052
public class AotProcessor {
5153

54+
private static final Consumer<ExecutableHint.Builder> INVOKE_CONSTRUCTOR_HINT = (hint) -> hint
55+
.setModes(ExecutableMode.INVOKE);
56+
5257
private final Class<?> application;
5358

5459
private final String[] applicationArgs;
@@ -57,6 +62,8 @@ public class AotProcessor {
5762

5863
private final Path resourceOutput;
5964

65+
private final Path classOutput;
66+
6067
private final String groupId;
6168

6269
private final String artifactId;
@@ -67,17 +74,19 @@ public class AotProcessor {
6774
* @param applicationArgs the arguments to provide to the main method
6875
* @param sourceOutput the location of generated sources
6976
* @param resourceOutput the location of generated resources
77+
* @param classOutput the location of generated classes
7078
* @param groupId the group ID of the application, used to locate
7179
* native-image.properties
7280
* @param artifactId the artifact ID of the application, used to locate
7381
* native-image.properties
7482
*/
7583
public AotProcessor(Class<?> application, String[] applicationArgs, Path sourceOutput, Path resourceOutput,
76-
String groupId, String artifactId) {
84+
Path classOutput, String groupId, String artifactId) {
7785
this.application = application;
7886
this.applicationArgs = applicationArgs;
7987
this.sourceOutput = sourceOutput;
8088
this.resourceOutput = resourceOutput;
89+
this.classOutput = classOutput;
8190
this.groupId = groupId;
8291
this.artifactId = artifactId;
8392
}
@@ -104,36 +113,39 @@ private void callApplicationMainMethod() {
104113
}
105114

106115
private void performAotProcessing(GenericApplicationContext applicationContext) {
107-
DefaultGeneratedTypeContext generationContext = new DefaultGeneratedTypeContext(
108-
this.application.getPackageName(), (packageName) -> GeneratedType.of(ClassName.get(packageName,
109-
this.application.getSimpleName() + "__ApplicationContextInitializer")));
116+
FileSystemGeneratedFiles generatedFiles = new FileSystemGeneratedFiles(this::getRoot);
117+
DefaultGenerationContext generationContext = new DefaultGenerationContext(generatedFiles);
110118
ApplicationContextAotGenerator generator = new ApplicationContextAotGenerator();
111-
generator.generateApplicationContext(applicationContext, generationContext);
112-
113-
// Register reflection hint for entry point as we access it via reflection
114-
generationContext.runtimeHints().reflection()
115-
.registerType(GeneratedTypeReference.of(generationContext.getMainGeneratedType().getClassName()),
116-
(hint) -> hint.onReachableType(TypeReference.of(this.application)).withConstructor(
117-
Collections.emptyList(),
118-
(constructorHint) -> constructorHint.setModes(ExecutableMode.INVOKE)));
119-
120-
writeGeneratedSources(generationContext.toJavaFiles());
121-
writeGeneratedResources(generationContext.runtimeHints());
119+
ClassName generatedInitializerClassName = generationContext.getClassNameGenerator()
120+
.generateClassName(this.application, "ApplicationContextInitializer");
121+
generator.generateApplicationContext(applicationContext, generationContext, generatedInitializerClassName);
122+
registerEntryPointHint(generationContext, generatedInitializerClassName);
123+
generationContext.writeGeneratedContent();
124+
writeHints(generationContext.getRuntimeHints());
122125
writeNativeImageProperties();
123126
}
124127

125-
private void writeGeneratedSources(List<JavaFile> sources) {
126-
for (JavaFile source : sources) {
127-
try {
128-
source.writeTo(this.sourceOutput);
129-
}
130-
catch (IOException ex) {
131-
throw new IllegalStateException("Failed to write " + source.typeSpec.name, ex);
132-
}
128+
private void registerEntryPointHint(DefaultGenerationContext generationContext,
129+
ClassName generatedInitializerClassName) {
130+
TypeReference generatedType = TypeReference.of(generatedInitializerClassName.canonicalName());
131+
TypeReference applicationType = TypeReference.of(this.application);
132+
generationContext.getRuntimeHints().reflection().registerType(generatedType, (hint) -> hint
133+
.onReachableType(applicationType).withConstructor(Collections.emptyList(), INVOKE_CONSTRUCTOR_HINT));
134+
}
135+
136+
private Path getRoot(Kind kind) {
137+
switch (kind) {
138+
case SOURCE:
139+
return this.sourceOutput;
140+
case RESOURCE:
141+
return this.resourceOutput;
142+
case CLASS:
143+
return this.classOutput;
133144
}
145+
throw new IllegalStateException("Unsupported kind " + kind);
134146
}
135147

136-
private void writeGeneratedResources(RuntimeHints hints) {
148+
private void writeHints(RuntimeHints hints) {
137149
FileNativeConfigurationWriter writer = new FileNativeConfigurationWriter(this.resourceOutput, this.groupId,
138150
this.artifactId);
139151
writer.write(hints);
@@ -164,21 +176,22 @@ private void writeNativeImageProperties() {
164176
}
165177

166178
public static void main(String[] args) throws Exception {
167-
int requiredArgs = 5;
179+
int requiredArgs = 6;
168180
if (args.length < requiredArgs) {
169181
throw new IllegalArgumentException("Usage: " + AotProcessor.class.getName()
170-
+ " <applicationName> <sourceOutput> <resourceOutput> <groupId> <artifactId> <originalArgs...>");
182+
+ " <applicationName> <sourceOutput> <resourceOutput> <classOutput> <groupId> <artifactId> <originalArgs...>");
171183
}
172184
String applicationName = args[0];
173185
Path sourceOutput = Paths.get(args[1]);
174186
Path resourceOutput = Paths.get(args[2]);
175-
String groupId = args[3];
176-
String artifactId = args[4];
187+
Path classOutput = Paths.get(args[3]);
188+
String groupId = args[4];
189+
String artifactId = args[5];
177190
String[] applicationArgs = (args.length > requiredArgs) ? Arrays.copyOfRange(args, requiredArgs, args.length)
178191
: new String[0];
179192
Class<?> application = Class.forName(applicationName);
180-
AotProcessor aotProcess = new AotProcessor(application, applicationArgs, sourceOutput, resourceOutput, groupId,
181-
artifactId);
193+
AotProcessor aotProcess = new AotProcessor(application, applicationArgs, sourceOutput, resourceOutput,
194+
classOutput, groupId, artifactId);
182195
aotProcess.process();
183196
}
184197

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/AotProcessorTests.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ void setup() {
4545
void processApplicationInvokesRunMethod(@TempDir Path directory) {
4646
String[] arguments = new String[] { "1", "2" };
4747
AotProcessor processor = new AotProcessor(SampleApplication.class, arguments, directory.resolve("source"),
48-
directory.resolve("resource"), "com.example", "example");
48+
directory.resolve("resource"), directory.resolve("class"), "com.example", "example");
4949
processor.process();
5050
assertThat(SampleApplication.argsHolder).isEqualTo(arguments);
5151
assertThat(directory).satisfies(hasGeneratedAssetsForSampleApplication());
@@ -54,7 +54,7 @@ void processApplicationInvokesRunMethod(@TempDir Path directory) {
5454
@Test
5555
void processApplicationWithMainMethodThatDoesNotRun(@TempDir Path directory) {
5656
AotProcessor processor = new AotProcessor(BrokenApplication.class, new String[0], directory.resolve("source"),
57-
directory.resolve("resource"), "com.example", "example");
57+
directory.resolve("resource"), directory.resolve("class"), "com.example", "example");
5858
assertThatIllegalArgumentException().isThrownBy(processor::process)
5959
.withMessageContaining("Does it run a SpringApplication?");
6060
assertThat(directory).isEmptyDirectory();
@@ -63,8 +63,8 @@ void processApplicationWithMainMethodThatDoesNotRun(@TempDir Path directory) {
6363
@Test
6464
void invokeMainParseArgumentsAndInvokesRunMethod(@TempDir Path directory) throws Exception {
6565
String[] mainArguments = new String[] { SampleApplication.class.getName(),
66-
directory.resolve("source").toString(), directory.resolve("resource").toString(), "com.example",
67-
"example", "1", "2" };
66+
directory.resolve("source").toString(), directory.resolve("resource").toString(),
67+
directory.resolve("class").toString(), "com.example", "example", "1", "2" };
6868
AotProcessor.main(mainArguments);
6969
assertThat(SampleApplication.argsHolder).containsExactly("1", "2");
7070
assertThat(directory).satisfies(hasGeneratedAssetsForSampleApplication());
@@ -78,8 +78,8 @@ void invokeMainWithMissingArguments() {
7878

7979
private Consumer<Path> hasGeneratedAssetsForSampleApplication() {
8080
return (directory) -> {
81-
assertThat(directory
82-
.resolve("source/org/springframework/boot/SampleApplication__ApplicationContextInitializer.java"))
81+
assertThat(directory.resolve(
82+
"source/org/springframework/boot/AotProcessorTests_SampleApplication__ApplicationContextInitializer.java"))
8383
.exists().isRegularFile();
8484
assertThat(directory.resolve("resource/META-INF/native-image/com.example/example/reflect-config.json"))
8585
.exists().isRegularFile();

0 commit comments

Comments
 (0)