diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/system/DevToolsEnablementDeducer.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/system/DevToolsEnablementDeducer.java
index 435ee4704a..da76267952 100644
--- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/system/DevToolsEnablementDeducer.java
+++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/system/DevToolsEnablementDeducer.java
@@ -20,7 +20,7 @@ import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
-import org.springframework.boot.AotProcessor;
+import org.springframework.boot.SpringApplicationAotProcessor;
/**
* Utility to deduce if DevTools should be enabled in the current context.
@@ -37,7 +37,7 @@ public final class DevToolsEnablementDeducer {
skipped.add("org.junit.runners.");
skipped.add("org.junit.platform.");
skipped.add("org.springframework.boot.test.");
- skipped.add(AotProcessor.class.getName());
+ skipped.add(SpringApplicationAotProcessor.class.getName());
skipped.add("cucumber.runtime.");
SKIPPED_STACK_ELEMENTS = Collections.unmodifiableSet(skipped);
}
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/ProcessAot.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/ProcessAot.java
index 66dde61062..bad9aef2ec 100644
--- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/ProcessAot.java
+++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/ProcessAot.java
@@ -38,7 +38,7 @@ public class ProcessAot extends AbstractAot {
public ProcessAot() {
this.applicationClass = getProject().getObjects().property(String.class);
- getMainClass().set("org.springframework.boot.AotProcessor");
+ getMainClass().set("org.springframework.boot.SpringApplicationAotProcessor");
}
@Input
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests.java
index 047848ca2c..50442f4426 100644
--- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests.java
+++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests.java
@@ -55,7 +55,7 @@ class NativeImagePluginActionIntegrationTests {
@TestTemplate
void reachabilityMetadataConfigurationFilesAreCopiedToJar() throws IOException {
- writeDummyAotProcessorMainClass();
+ writeDummySpringApplicationAotProcessorMainClass();
BuildResult result = this.gradleBuild.build("bootJar");
assertThat(result.task(":bootJar").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
File buildLibs = new File(this.gradleBuild.getProjectDir(), "build/libs");
@@ -71,7 +71,7 @@ class NativeImagePluginActionIntegrationTests {
@TestTemplate
void reachabilityMetadataConfigurationFilesFromFileRepositoryAreCopiedToJar() throws IOException {
- writeDummyAotProcessorMainClass();
+ writeDummySpringApplicationAotProcessorMainClass();
FileSystemUtils.copyRecursively(new File("src/test/resources/reachability-metadata-repository"),
new File(this.gradleBuild.getProjectDir(), "reachability-metadata-repository"));
BuildResult result = this.gradleBuild.build("bootJar");
@@ -87,16 +87,16 @@ class NativeImagePluginActionIntegrationTests {
"META-INF/native-image/org.jline/jline/3.21.0/resource-config.json");
}
- private void writeDummyAotProcessorMainClass() {
+ private void writeDummySpringApplicationAotProcessorMainClass() {
File examplePackage = new File(this.gradleBuild.getProjectDir(), "src/main/java/org/springframework/boot");
examplePackage.mkdirs();
- File main = new File(examplePackage, "AotProcessor.java");
+ File main = new File(examplePackage, "SpringApplicationAotProcessor.java");
try (PrintWriter writer = new PrintWriter(new FileWriter(main))) {
writer.println("package org.springframework.boot;");
writer.println();
writer.println("import java.io.IOException;");
writer.println();
- writer.println("public class AotProcessor {");
+ writer.println("public class SpringApplicationAotProcessor {");
writer.println();
writer.println(" public static void main(String[] args) {");
writer.println(" }");
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests.java
index 00aa32533d..963d54a5e1 100644
--- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests.java
+++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests.java
@@ -103,7 +103,7 @@ class SpringBootAotPluginIntegrationTests {
@TestTemplate
void processAotRunsWhenProjectHasMainSource() throws IOException {
- writeMainClass("org.springframework.boot", "AotProcessor");
+ writeMainClass("org.springframework.boot", "SpringApplicationAotProcessor");
writeMainClass("com.example", "Main");
assertThat(this.gradleBuild.build("processAot").task(":processAot").getOutcome())
.isEqualTo(TaskOutcome.SUCCESS);
diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ProcessAotMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ProcessAotMojo.java
index 5d645b6b11..01707b27bc 100644
--- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ProcessAotMojo.java
+++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ProcessAotMojo.java
@@ -40,7 +40,7 @@ import org.springframework.util.ObjectUtils;
requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME)
public class ProcessAotMojo extends AbstractAotMojo {
- private static final String AOT_PROCESSOR_CLASS_NAME = "org.springframework.boot.AotProcessor";
+ private static final String AOT_PROCESSOR_CLASS_NAME = "org.springframework.boot.SpringApplicationAotProcessor";
/**
* Directory containing the classes and resource files that should be packaged into
diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/AotProcessor.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/AotProcessor.java
deleted file mode 100644
index 46c8c70015..0000000000
--- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/AotProcessor.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright 2012-2022 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.boot;
-
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.springframework.aot.generate.ClassNameGenerator;
-import org.springframework.aot.generate.DefaultGenerationContext;
-import org.springframework.aot.generate.FileSystemGeneratedFiles;
-import org.springframework.aot.generate.GeneratedFiles.Kind;
-import org.springframework.aot.hint.ExecutableMode;
-import org.springframework.aot.hint.ReflectionHints;
-import org.springframework.aot.hint.RuntimeHints;
-import org.springframework.aot.hint.TypeReference;
-import org.springframework.aot.nativex.FileNativeConfigurationWriter;
-import org.springframework.boot.SpringApplication.AbandonedRunException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.context.aot.ApplicationContextAotGenerator;
-import org.springframework.context.support.GenericApplicationContext;
-import org.springframework.javapoet.ClassName;
-import org.springframework.util.Assert;
-import org.springframework.util.FileSystemUtils;
-import org.springframework.util.ReflectionUtils;
-import org.springframework.util.function.ThrowingSupplier;
-
-/**
- * Entry point for AOT processing of a {@link SpringApplication}.
- *
- * For internal use only.
- *
- * @author Stephane Nicoll
- * @author Andy Wilkinson
- * @author Phillip Webb
- * @since 3.0.0
- */
-public class AotProcessor {
-
- private final Class> application;
-
- private final String[] applicationArgs;
-
- private final Path sourceOutput;
-
- private final Path resourceOutput;
-
- private final Path classOutput;
-
- private final String groupId;
-
- private final String artifactId;
-
- /**
- * Create a new processor for the specified application and settings.
- * @param application the application main class
- * @param applicationArgs the arguments to provide to the main method
- * @param sourceOutput the location of generated sources
- * @param resourceOutput the location of generated resources
- * @param classOutput the location of generated classes
- * @param groupId the group ID of the application, used to locate
- * native-image.properties
- * @param artifactId the artifact ID of the application, used to locate
- * native-image.properties
- */
- public AotProcessor(Class> application, String[] applicationArgs, Path sourceOutput, Path resourceOutput,
- Path classOutput, String groupId, String artifactId) {
- this.application = application;
- this.applicationArgs = applicationArgs;
- this.sourceOutput = sourceOutput;
- this.resourceOutput = resourceOutput;
- this.classOutput = classOutput;
- this.groupId = groupId;
- this.artifactId = artifactId;
- }
-
- /**
- * Trigger the processing of the application managed by this instance.
- */
- public void process() {
- deleteExistingOutput();
- GenericApplicationContext applicationContext = new AotProcessorHook().run(() -> {
- Method mainMethod = this.application.getMethod("main", String[].class);
- return ReflectionUtils.invokeMethod(mainMethod, null, new Object[] { this.applicationArgs });
- });
- performAotProcessing(applicationContext);
- }
-
- private void deleteExistingOutput() {
- deleteExistingOutput(this.sourceOutput, this.resourceOutput, this.classOutput);
- }
-
- private void deleteExistingOutput(Path... paths) {
- for (Path path : paths) {
- try {
- FileSystemUtils.deleteRecursively(path);
- }
- catch (IOException ex) {
- throw new RuntimeException("Failed to delete existing output in '" + path + "'");
- }
- }
- }
-
- private void performAotProcessing(GenericApplicationContext applicationContext) {
- FileSystemGeneratedFiles generatedFiles = new FileSystemGeneratedFiles(this::getRoot);
- DefaultGenerationContext generationContext = new DefaultGenerationContext(
- new ClassNameGenerator(ClassName.get(this.application)), generatedFiles);
- ApplicationContextAotGenerator generator = new ApplicationContextAotGenerator();
- ClassName generatedInitializerClassName = generator.processAheadOfTime(applicationContext, generationContext);
- registerEntryPointHint(generationContext, generatedInitializerClassName);
- generationContext.writeGeneratedContent();
- writeHints(generationContext.getRuntimeHints());
- writeNativeImageProperties();
- }
-
- private void registerEntryPointHint(DefaultGenerationContext generationContext,
- ClassName generatedInitializerClassName) {
- TypeReference generatedType = TypeReference.of(generatedInitializerClassName.canonicalName());
- TypeReference applicationType = TypeReference.of(this.application);
- ReflectionHints reflection = generationContext.getRuntimeHints().reflection();
- reflection.registerType(applicationType);
- reflection.registerType(generatedType, (typeHint) -> typeHint.onReachableType(applicationType)
- .withConstructor(Collections.emptyList(), ExecutableMode.INVOKE));
- }
-
- private Path getRoot(Kind kind) {
- return switch (kind) {
- case SOURCE -> this.sourceOutput;
- case RESOURCE -> this.resourceOutput;
- case CLASS -> this.classOutput;
- };
- }
-
- private void writeHints(RuntimeHints hints) {
- FileNativeConfigurationWriter writer = new FileNativeConfigurationWriter(this.resourceOutput, this.groupId,
- this.artifactId);
- writer.write(hints);
- }
-
- private void writeNativeImageProperties() {
- List args = new ArrayList<>();
- args.add("-H:Class=" + this.application.getName());
- args.add("--report-unsupported-elements-at-runtime");
- args.add("--no-fallback");
- args.add("--install-exit-handlers");
- StringBuilder sb = new StringBuilder();
- sb.append("Args = ");
- sb.append(String.join(String.format(" \\%n"), args));
- Path file = this.resourceOutput
- .resolve("META-INF/native-image/" + this.groupId + "/" + this.artifactId + "/native-image.properties");
- try {
- if (!Files.exists(file)) {
- Files.createDirectories(file.getParent());
- Files.createFile(file);
- }
- Files.writeString(file, sb.toString());
- }
- catch (IOException ex) {
- throw new IllegalStateException("Failed to write native-image properties", ex);
- }
- }
-
- public static void main(String[] args) throws Exception {
- int requiredArgs = 6;
- Assert.isTrue(args.length >= requiredArgs, () -> "Usage: " + AotProcessor.class.getName()
- + " ");
- String applicationName = args[0];
- Path sourceOutput = Paths.get(args[1]);
- Path resourceOutput = Paths.get(args[2]);
- Path classOutput = Paths.get(args[3]);
- String groupId = args[4];
- String artifactId = args[5];
- String[] applicationArgs = (args.length > requiredArgs) ? Arrays.copyOfRange(args, requiredArgs, args.length)
- : new String[0];
- Class> application = Class.forName(applicationName);
- new AotProcessor(application, applicationArgs, sourceOutput, resourceOutput, classOutput, groupId, artifactId)
- .process();
- }
-
- /**
- * {@link SpringApplicationHook} used to capture the {@link ApplicationContext} and
- * trigger early exit of main method.
- */
- private class AotProcessorHook implements SpringApplicationHook {
-
- @Override
- public SpringApplicationRunListener getRunListener(SpringApplication application) {
- return new SpringApplicationRunListener() {
-
- @Override
- public void contextLoaded(ConfigurableApplicationContext context) {
- throw new AbandonedRunException(context);
- }
-
- };
- }
-
- private GenericApplicationContext run(ThrowingSupplier action) {
- try {
- SpringApplication.withHook(this, action);
- }
- catch (AbandonedRunException ex) {
- ApplicationContext context = ex.getApplicationContext();
- Assert.isInstanceOf(GenericApplicationContext.class, context,
- () -> "AOT processing requires a GenericApplicationContext but got a "
- + context.getClass().getName());
- return (GenericApplicationContext) context;
- }
- throw new IllegalStateException(
- "No application context available after calling main method of '%s'. Does it run a SpringApplication?"
- .formatted(AotProcessor.this.application.getName()));
- }
-
- }
-
-}
diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationAotProcessor.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationAotProcessor.java
new file mode 100644
index 0000000000..8fea5e8a68
--- /dev/null
+++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationAotProcessor.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot;
+
+import java.lang.reflect.Method;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+import org.springframework.boot.SpringApplication.AbandonedRunException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.aot.AotProcessor;
+import org.springframework.context.support.GenericApplicationContext;
+import org.springframework.util.Assert;
+import org.springframework.util.ReflectionUtils;
+import org.springframework.util.function.ThrowingSupplier;
+
+/**
+ * Entry point for AOT processing of a {@link SpringApplication}.
+ *
+ * For internal use only.
+ *
+ * @author Stephane Nicoll
+ * @author Andy Wilkinson
+ * @author Phillip Webb
+ * @since 3.0.0
+ */
+public class SpringApplicationAotProcessor extends AotProcessor {
+
+ private final String[] applicationArgs;
+
+ /**
+ * Create a new processor for the specified application and settings.
+ * @param application the application main class
+ * @param applicationArgs the arguments to provide to the main method
+ * @param sourceOutput the location of generated sources
+ * @param resourceOutput the location of generated resources
+ * @param classOutput the location of generated classes
+ * @param groupId the group ID of the application, used to locate
+ * native-image.properties
+ * @param artifactId the artifact ID of the application, used to locate
+ * native-image.properties
+ */
+ public SpringApplicationAotProcessor(Class> application, String[] applicationArgs, Path sourceOutput,
+ Path resourceOutput, Path classOutput, String groupId, String artifactId) {
+ super(application, sourceOutput, resourceOutput, classOutput, groupId, artifactId);
+ this.applicationArgs = applicationArgs;
+ }
+
+ @Override
+ protected GenericApplicationContext prepareApplicationContext(Class> application) {
+ return new AotProcessorHook(application).run(() -> {
+ Method mainMethod = application.getMethod("main", String[].class);
+ return ReflectionUtils.invokeMethod(mainMethod, null, new Object[] { this.applicationArgs });
+ });
+ }
+
+ public static void main(String[] args) throws Exception {
+ int requiredArgs = 6;
+ Assert.isTrue(args.length >= requiredArgs, () -> "Usage: " + SpringApplicationAotProcessor.class.getName()
+ + " ");
+ String applicationName = args[0];
+ Path sourceOutput = Paths.get(args[1]);
+ Path resourceOutput = Paths.get(args[2]);
+ Path classOutput = Paths.get(args[3]);
+ String groupId = args[4];
+ String artifactId = args[5];
+ String[] applicationArgs = (args.length > requiredArgs) ? Arrays.copyOfRange(args, requiredArgs, args.length)
+ : new String[0];
+ Class> application = Class.forName(applicationName);
+ new SpringApplicationAotProcessor(application, applicationArgs, sourceOutput, resourceOutput, classOutput,
+ groupId, artifactId).process();
+ }
+
+ /**
+ * {@link SpringApplicationHook} used to capture the {@link ApplicationContext} and
+ * trigger early exit of main method.
+ */
+ private static final class AotProcessorHook implements SpringApplicationHook {
+
+ private final Class> application;
+
+ private AotProcessorHook(Class> application) {
+ this.application = application;
+ }
+
+ @Override
+ public SpringApplicationRunListener getRunListener(SpringApplication application) {
+ return new SpringApplicationRunListener() {
+
+ @Override
+ public void contextLoaded(ConfigurableApplicationContext context) {
+ throw new AbandonedRunException(context);
+ }
+
+ };
+ }
+
+ private GenericApplicationContext run(ThrowingSupplier action) {
+ try {
+ SpringApplication.withHook(this, action);
+ }
+ catch (AbandonedRunException ex) {
+ ApplicationContext context = ex.getApplicationContext();
+ Assert.isInstanceOf(GenericApplicationContext.class, context,
+ () -> "AOT processing requires a GenericApplicationContext but got a "
+ + context.getClass().getName());
+ return (GenericApplicationContext) context;
+ }
+ throw new IllegalStateException(
+ "No application context available after calling main method of '%s'. Does it run a SpringApplication?"
+ .formatted(this.application.getName()));
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/AotProcessorTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/AotProcessorTests.java
deleted file mode 100644
index 4d65218a92..0000000000
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/AotProcessorTests.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright 2012-2022 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.boot;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.function.Consumer;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.io.TempDir;
-
-import org.springframework.context.annotation.Configuration;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
-import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
-
-/**
- * Tests for {@link AotProcessor}.
- *
- * @author Stephane Nicoll
- * @author Andy Wilkinson
- */
-class AotProcessorTests {
-
- @BeforeEach
- void setup() {
- SampleApplication.argsHolder = null;
- SampleApplication.postRunInvoked = false;
- }
-
- @Test
- void processApplicationInvokesRunMethod(@TempDir Path directory) throws IOException {
- String[] arguments = new String[] { "1", "2" };
- AotProcessor processor = new AotProcessor(SampleApplication.class, arguments, directory.resolve("source"),
- directory.resolve("resource"), directory.resolve("class"), "com.example", "example");
- processor.process();
- assertThat(SampleApplication.argsHolder).isEqualTo(arguments);
- assertThat(SampleApplication.postRunInvoked).isFalse();
- assertThat(directory).satisfies(hasGeneratedAssetsForSampleApplication());
- }
-
- @Test
- void processApplicationWithMainMethodThatDoesNotRun(@TempDir Path directory) {
- AotProcessor processor = new AotProcessor(BrokenApplication.class, new String[0], directory.resolve("source"),
- directory.resolve("resource"), directory.resolve("class"), "com.example", "example");
- assertThatIllegalStateException().isThrownBy(processor::process)
- .withMessageContaining("Does it run a SpringApplication?");
- assertThat(directory).isEmptyDirectory();
- }
-
- @Test
- void invokeMainParseArgumentsAndInvokesRunMethod(@TempDir Path directory) throws Exception {
- String[] mainArguments = new String[] { SampleApplication.class.getName(),
- directory.resolve("source").toString(), directory.resolve("resource").toString(),
- directory.resolve("class").toString(), "com.example", "example", "1", "2" };
- AotProcessor.main(mainArguments);
- assertThat(SampleApplication.argsHolder).containsExactly("1", "2");
- assertThat(SampleApplication.postRunInvoked).isFalse();
- assertThat(directory).satisfies(hasGeneratedAssetsForSampleApplication());
- }
-
- @Test
- void invokeMainWithMissingArguments() {
- assertThatIllegalArgumentException().isThrownBy(() -> AotProcessor.main(new String[] { "Test" }))
- .withMessageContaining("Usage:");
- }
-
- @Test
- void processingDeletesExistingOutput(@TempDir Path directory) throws IOException {
- Path sourceOutput = directory.resolve("source");
- Path resourceOutput = directory.resolve("resource");
- Path classOutput = directory.resolve("class");
- Path existingSourceOutput = createExisting(sourceOutput);
- Path existingResourceOutput = createExisting(resourceOutput);
- Path existingClassOutput = createExisting(classOutput);
- AotProcessor processor = new AotProcessor(SampleApplication.class, new String[0], sourceOutput, resourceOutput,
- classOutput, "com.example", "example");
- processor.process();
- assertThat(existingSourceOutput).doesNotExist();
- assertThat(existingResourceOutput).doesNotExist();
- assertThat(existingClassOutput).doesNotExist();
- }
-
- private Path createExisting(Path directory) throws IOException {
- Path existing = directory.resolve("existing");
- Files.createDirectories(directory);
- Files.createFile(existing);
- return existing;
- }
-
- private Consumer hasGeneratedAssetsForSampleApplication() {
- return (directory) -> {
- assertThat(directory.resolve(
- "source/org/springframework/boot/AotProcessorTests_SampleApplication__ApplicationContextInitializer.java"))
- .exists().isRegularFile();
- assertThat(directory.resolve("source/org/springframework/boot/AotProcessorTests__BeanDefinitions.java"))
- .exists().isRegularFile();
- assertThat(directory.resolve(
- "source/org/springframework/boot/AotProcessorTests_SampleApplication__BeanFactoryRegistrations.java"))
- .exists().isRegularFile();
- assertThat(directory.resolve("resource/META-INF/native-image/com.example/example/reflect-config.json"))
- .exists().isRegularFile();
- Path nativeImagePropertiesFile = directory
- .resolve("resource/META-INF/native-image/com.example/example/native-image.properties");
- assertThat(nativeImagePropertiesFile).exists().isRegularFile().hasContent("""
- Args = -H:Class=org.springframework.boot.AotProcessorTests$SampleApplication \\
- --report-unsupported-elements-at-runtime \\
- --no-fallback \\
- --install-exit-handlers
- """);
- };
- }
-
- @Configuration(proxyBeanMethods = false)
- public static class SampleApplication {
-
- public static String[] argsHolder;
-
- public static boolean postRunInvoked;
-
- public static void main(String[] args) {
- argsHolder = args;
- SpringApplication.run(SampleApplication.class, args);
- postRunInvoked = true;
- }
-
- }
-
- public static class BrokenApplication {
-
- public static void main(String[] args) {
- // Does not run an application
- }
-
- }
-
-}
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationAotProcessorTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationAotProcessorTests.java
new file mode 100644
index 0000000000..047d8cc747
--- /dev/null
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationAotProcessorTests.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012-2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot;
+
+import java.nio.file.Path;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import org.springframework.context.annotation.Configuration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
+
+/**
+ * Tests for {@link SpringApplicationAotProcessor}.
+ *
+ * @author Stephane Nicoll
+ * @author Andy Wilkinson
+ */
+class SpringApplicationAotProcessorTests {
+
+ @BeforeEach
+ void setup() {
+ SampleApplication.argsHolder = null;
+ SampleApplication.postRunInvoked = false;
+ }
+
+ @Test
+ void processApplicationInvokesRunMethod(@TempDir Path directory) {
+ String[] arguments = new String[] { "1", "2" };
+ SpringApplicationAotProcessor processor = new SpringApplicationAotProcessor(SampleApplication.class, arguments,
+ directory.resolve("source"), directory.resolve("resource"), directory.resolve("class"), "com.example",
+ "example");
+ processor.process();
+ assertThat(SampleApplication.argsHolder).isEqualTo(arguments);
+ assertThat(SampleApplication.postRunInvoked).isFalse();
+ }
+
+ @Test
+ void processApplicationWithMainMethodThatDoesNotRun(@TempDir Path directory) {
+ SpringApplicationAotProcessor processor = new SpringApplicationAotProcessor(BrokenApplication.class,
+ new String[0], directory.resolve("source"), directory.resolve("resource"), directory.resolve("class"),
+ "com.example", "example");
+ assertThatIllegalStateException().isThrownBy(processor::process)
+ .withMessageContaining("Does it run a SpringApplication?");
+ assertThat(directory).isEmptyDirectory();
+ }
+
+ @Test
+ void invokeMainParseArgumentsAndInvokesRunMethod(@TempDir Path directory) throws Exception {
+ String[] mainArguments = new String[] { SampleApplication.class.getName(),
+ directory.resolve("source").toString(), directory.resolve("resource").toString(),
+ directory.resolve("class").toString(), "com.example", "example", "1", "2" };
+ SpringApplicationAotProcessor.main(mainArguments);
+ assertThat(SampleApplication.argsHolder).containsExactly("1", "2");
+ assertThat(SampleApplication.postRunInvoked).isFalse();
+ }
+
+ @Test
+ void invokeMainWithMissingArguments() {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> SpringApplicationAotProcessor.main(new String[] { "Test" }))
+ .withMessageContaining("Usage:");
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ public static class SampleApplication {
+
+ public static String[] argsHolder;
+
+ public static boolean postRunInvoked;
+
+ public static void main(String[] args) {
+ argsHolder = args;
+ SpringApplication.run(SampleApplication.class, args);
+ postRunInvoked = true;
+ }
+
+ }
+
+ public static class BrokenApplication {
+
+ public static void main(String[] args) {
+ // Does not run an application
+ }
+
+ }
+
+}