Adapt to breaking changes to AOT processing entry points

See gh-32550
This commit is contained in:
Andy Wilkinson 2022-10-10 22:02:25 +01:00
parent d870474fcd
commit d351086a06
7 changed files with 89 additions and 29 deletions

View File

@ -0,0 +1,60 @@
/*
* 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.test.context;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.test.context.aot.TestAotProcessor;
import org.springframework.util.Assert;
/**
* Entry point for AOT processing of a Spring Boot application's tests.
*
* <strong>For internal use only.</strong>
*
* @author Andy Wilkinson
* @since 3.0.0
*/
public class SpringBootTestAotProcessor extends TestAotProcessor {
/**
* Create a new processor for the specified test classpath roots and general settings.
* @param classpathRoots the classpath roots to scan for test classes
* @param settings the general AOT processor settings
*/
public SpringBootTestAotProcessor(Set<Path> classpathRoots, Settings settings) {
super(classpathRoots, settings);
}
public static void main(String[] args) {
int requiredArgs = 6;
Assert.isTrue(args.length >= requiredArgs,
() -> "Usage: %s <classpathRoots> <sourceOutput> <resourceOutput> <classOutput> <groupId> <artifactId>"
.formatted(TestAotProcessor.class.getName()));
Set<Path> classpathRoots = Arrays.stream(args[0].split(File.pathSeparator)).map(Paths::get)
.collect(Collectors.toSet());
Settings settings = new Settings().setSourceOutput(Paths.get(args[1])).setResourceOutput(Paths.get(args[2]))
.setClassOutput(Paths.get(args[3])).setGroupId(args[4]).setArtifactId(args[5]);
new SpringBootTestAotProcessor(classpathRoots, settings).process();
}
}

View File

@ -45,7 +45,7 @@ public class ProcessTestAot extends AbstractAot {
private final Configuration junitPlatformLauncher;
public ProcessTestAot() {
getMainClass().set("org.springframework.test.context.aot.TestAotProcessor");
getMainClass().set("org.springframework.boot.test.context.SpringBootTestAotProcessor");
this.junitPlatformLauncher = createJUnitPlatformLauncher();
}

View File

@ -55,6 +55,7 @@ dependencies {
}
mavenRepository(project(path: ":spring-boot-project:spring-boot", configuration: "mavenRepository"))
mavenRepository(project(path: ":spring-boot-project:spring-boot-test", configuration: "mavenRepository"))
runtimeOnly("org.sonatype.plexus:plexus-build-api")

View File

@ -44,6 +44,12 @@
<version>@spring-framework.version@</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>@project.version@</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>

View File

@ -58,7 +58,7 @@ public class ProcessTestAotMojo extends AbstractAotMojo {
private static final String JUNIT_PLATFORM_LAUNCHER_ARTIFACT_ID = "junit-platform-launcher";
private static final String AOT_PROCESSOR_CLASS_NAME = "org.springframework.test.context.aot.TestAotProcessor";
private static final String AOT_PROCESSOR_CLASS_NAME = "org.springframework.boot.test.context.SpringBootTestAotProcessor";
/**
* Directory containing the classes and resource files that should be packaged into

View File

@ -17,14 +17,13 @@
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.aot.ContextAotProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
@ -40,25 +39,18 @@ import org.springframework.util.function.ThrowingSupplier;
* @author Phillip Webb
* @since 3.0.0
*/
public class SpringApplicationAotProcessor extends AotProcessor {
public class SpringApplicationAotProcessor extends ContextAotProcessor {
private final String[] applicationArgs;
/**
* Create a new processor for the specified application and settings.
* @param application the application main class
* @param settings the general AOT processor settings
* @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);
public SpringApplicationAotProcessor(Class<?> application, Settings settings, String[] applicationArgs) {
super(application, settings);
this.applicationArgs = applicationArgs;
}
@ -74,17 +66,12 @@ public class SpringApplicationAotProcessor extends AotProcessor {
int requiredArgs = 6;
Assert.isTrue(args.length >= requiredArgs, () -> "Usage: " + SpringApplicationAotProcessor.class.getName()
+ " <applicationName> <sourceOutput> <resourceOutput> <classOutput> <groupId> <artifactId> <originalArgs...>");
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];
Class<?> application = Class.forName(args[0]);
Settings settings = new Settings().setSourceOutput(Paths.get(args[1])).setResourceOutput(Paths.get(args[2]))
.setClassOutput(Paths.get(args[3])).setGroupId(args[4]).setArtifactId(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();
new SpringApplicationAotProcessor(application, settings, applicationArgs).process();
}
/**

View File

@ -23,6 +23,7 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.aot.AbstractAotProcessor.Settings;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
@ -45,9 +46,8 @@ class SpringApplicationAotProcessorTests {
@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");
SpringApplicationAotProcessor processor = new SpringApplicationAotProcessor(SampleApplication.class,
settings(directory), arguments);
processor.process();
assertThat(SampleApplication.argsHolder).isEqualTo(arguments);
assertThat(SampleApplication.postRunInvoked).isFalse();
@ -56,8 +56,7 @@ class SpringApplicationAotProcessorTests {
@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");
settings(directory), new String[0]);
assertThatIllegalStateException().isThrownBy(processor::process)
.withMessageContaining("Does it run a SpringApplication?");
assertThat(directory).isEmptyDirectory();
@ -80,6 +79,13 @@ class SpringApplicationAotProcessorTests {
.withMessageContaining("Usage:");
}
private Settings settings(Path directory) {
return new Settings().setSourceOutput(directory.resolve("source"))
.setResourceOutput(directory.resolve("resource")).setClassOutput(directory.resolve("class"))
.setGroupId("com.example").setArtifactId("example");
}
@Configuration(proxyBeanMethods = false)
public static class SampleApplication {