Polish Gradle tasks for AOT processing

Closes gh-32946
pull/32951/head
Andy Wilkinson 2 years ago
parent bd75965ff8
commit 519250cacf

@ -19,6 +19,9 @@ package org.springframework.boot.gradle.plugin;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.DependencySet;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.attributes.Attribute;
import org.gradle.api.attributes.AttributeContainer;
import org.gradle.api.attributes.LibraryElements;
@ -119,7 +122,7 @@ public class SpringBootAotPlugin implements Plugin<Project> {
TaskProvider<ProcessAot> processAot = project.getTasks().register(PROCESS_AOT_TASK_NAME, ProcessAot.class,
(task) -> {
configureAotTask(project, aotSourceSet, task, mainSourceSet, resourcesOutput);
task.getApplicationClass()
task.getApplicationMainClass()
.set(resolveMainClassName.flatMap(ResolveMainClassName::readMainClassName));
task.setClasspath(aotClasspath);
});
@ -140,7 +143,6 @@ public class SpringBootAotPlugin implements Plugin<Project> {
.set(project.getLayout().getBuildDirectory().dir("generated/" + sourceSet.getName() + "Classes"));
task.getGroupId().set(project.provider(() -> String.valueOf(project.getGroup())));
task.getArtifactId().set(project.provider(() -> project.getName()));
task.setClasspathRoots(inputSourceSet.getOutput().getClassesDirs());
}
@SuppressWarnings("unchecked")
@ -171,6 +173,7 @@ public class SpringBootAotPlugin implements Plugin<Project> {
private void registerProcessTestAotTask(Project project, SourceSet mainSourceSet, SourceSet aotTestSourceSet,
SourceSet testSourceSet) {
Configuration aotClasspath = createAotProcessingClasspath(project, PROCESS_TEST_AOT_TASK_NAME, testSourceSet);
addJUnitPlatformLauncherDependency(project, aotClasspath);
Configuration compileClasspath = project.getConfigurations()
.getByName(aotTestSourceSet.getCompileClasspathConfigurationName());
compileClasspath.extendsFrom(aotClasspath);
@ -180,8 +183,7 @@ public class SpringBootAotPlugin implements Plugin<Project> {
ProcessTestAot.class, (task) -> {
configureAotTask(project, aotTestSourceSet, task, testSourceSet, resourcesOutput);
task.setClasspath(aotClasspath);
task.setTestRuntimeClasspath(
project.getConfigurations().getByName(testSourceSet.getImplementationConfigurationName()));
task.setClasspathRoots(testSourceSet.getOutput());
});
aotTestSourceSet.getJava().srcDir(processTestAot.map(ProcessTestAot::getSourcesOutput));
aotTestSourceSet.getResources().srcDir(resourcesOutput);
@ -194,4 +196,13 @@ public class SpringBootAotPlugin implements Plugin<Project> {
configureDependsOn(project, aotTestSourceSet, processTestAot);
}
private void addJUnitPlatformLauncherDependency(Project project, Configuration configuration) {
DependencyHandler dependencyHandler = project.getDependencies();
Dependency springBootDependencies = dependencyHandler
.create(dependencyHandler.platform(SpringBootPlugin.BOM_COORDINATES));
DependencySet dependencies = configuration.getDependencies();
dependencies.add(springBootDependencies);
dependencies.add(dependencyHandler.create("org.junit.platform:junit-platform-launcher"));
}
}

@ -20,17 +20,10 @@ import java.util.ArrayList;
import java.util.List;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileTree;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.IgnoreEmptyDirectories;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.JavaExec;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SkipWhenEmpty;
import org.gradle.work.DisableCachingByDefault;
/**
@ -53,8 +46,6 @@ public abstract class AbstractAot extends JavaExec {
private final Property<String> artifactId;
private FileCollection classpathRoots;
protected AbstractAot() {
this.sourcesDir = getProject().getObjects().directoryProperty();
this.resourcesDir = getProject().getObjects().directoryProperty();
@ -63,49 +54,51 @@ public abstract class AbstractAot extends JavaExec {
this.artifactId = getProject().getObjects().property(String.class);
}
/**
* The group ID of the application that is to be processed ahead-of-time.
* @return the group ID property
*/
@Input
public final Property<String> getGroupId() {
return this.groupId;
}
/**
* The artifact ID of the application that is to be processed ahead-of-time.
* @return the artifact ID property
*/
@Input
public final Property<String> getArtifactId() {
return this.artifactId;
}
/**
* The directory to which AOT-generated sources should be written.
* @return the sources directory property
*/
@OutputDirectory
public final DirectoryProperty getSourcesOutput() {
return this.sourcesDir;
}
/**
* The directory to which AOT-generated resources should be written.
* @return the resources directory property
*/
@OutputDirectory
public final DirectoryProperty getResourcesOutput() {
return this.resourcesDir;
}
/**
* The directory to which AOT-generated classes should be written.
* @return the classes directory property
*/
@OutputDirectory
public final DirectoryProperty getClassesOutput() {
return this.classesDir;
}
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
public final FileCollection getClasspathRoots() {
return this.classpathRoots;
}
@InputFiles
@SkipWhenEmpty
@IgnoreEmptyDirectories
@PathSensitive(PathSensitivity.RELATIVE)
final FileTree getInputClasses() {
return this.classpathRoots.getAsFileTree();
}
public void setClasspathRoots(FileCollection classpathRoots) {
this.classpathRoots = classpathRoots;
}
List<String> processorArgs() {
List<String> args = new ArrayList<>();
args.add(getSourcesOutput().getAsFile().get().getAbsolutePath());

@ -26,7 +26,7 @@ import org.gradle.api.tasks.JavaExec;
import org.gradle.api.tasks.TaskAction;
/**
* Custom {@link JavaExec} task for processing main code ahead-of-time.
* Custom {@link JavaExec} task for ahead-of-time processing of a Spring Boot application.
*
* @author Andy Wilkinson
* @since 3.0.0
@ -38,14 +38,18 @@ public abstract class ProcessAot extends AbstractAot {
getMainClass().set("org.springframework.boot.SpringApplicationAotProcessor");
}
/**
* Returns the main class of the application that is to be processed ahead-of-time.
* @return the application main class property
*/
@Input
public abstract Property<String> getApplicationClass();
public abstract Property<String> getApplicationMainClass();
@Override
@TaskAction
public void exec() {
List<String> args = new ArrayList<>();
args.add(getApplicationClass().get());
args.add(getApplicationMainClass().get());
args.addAll(processorArgs());
setArgs(args);
super.exec();

@ -21,20 +21,20 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.DependencySet;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileTree;
import org.gradle.api.tasks.CacheableTask;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.IgnoreEmptyDirectories;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.JavaExec;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SkipWhenEmpty;
import org.gradle.api.tasks.TaskAction;
import org.springframework.boot.gradle.util.VersionExtractor;
/**
* Custom {@link JavaExec} task for processing test code ahead-of-time.
* Custom {@link JavaExec} task for ahead-of-time processing of a Spring Boot
* application's tests.
*
* @author Andy Wilkinson
* @since 3.0.0
@ -42,28 +42,36 @@ import org.springframework.boot.gradle.util.VersionExtractor;
@CacheableTask
public class ProcessTestAot extends AbstractAot {
private final Configuration junitPlatformLauncher;
private FileCollection classpathRoots;
public ProcessTestAot() {
getMainClass().set("org.springframework.boot.test.context.SpringBootTestAotProcessor");
this.junitPlatformLauncher = createJUnitPlatformLauncher();
}
private Configuration createJUnitPlatformLauncher() {
Configuration configuration = getProject().getConfigurations().create(getName() + "JUnitPlatformLauncher");
DependencyHandler dependencyHandler = getProject().getDependencies();
Dependency springBootDependencies = dependencyHandler
.create(dependencyHandler.platform("org.springframework.boot:spring-boot-dependencies:"
+ VersionExtractor.forClass(ProcessTestAot.class)));
DependencySet dependencies = configuration.getDependencies();
dependencies.add(springBootDependencies);
dependencies.add(dependencyHandler.create("org.junit.platform:junit-platform-launcher"));
return configuration;
/**
* Returns the classpath roots that should be scanned for test classes to process.
* @return the classpath roots
*/
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
public final FileCollection getClasspathRoots() {
return this.classpathRoots;
}
/**
* Sets the classpath roots that should be scanned for test classes to process.
* @param classpathRoots the classpath roots
*/
public void setClasspathRoots(FileCollection classpathRoots) {
this.classpathRoots = classpathRoots;
}
@Classpath
FileCollection getJUnitPlatformLauncher() {
return this.junitPlatformLauncher;
@InputFiles
@SkipWhenEmpty
@IgnoreEmptyDirectories
@PathSensitive(PathSensitivity.RELATIVE)
final FileTree getInputClasses() {
return this.classpathRoots.getAsFileTree();
}
@Override
@ -74,12 +82,7 @@ public class ProcessTestAot extends AbstractAot {
.collect(Collectors.joining(File.pathSeparator)));
args.addAll(processorArgs());
setArgs(args);
classpath(this.junitPlatformLauncher);
super.exec();
}
public void setTestRuntimeClasspath(Configuration configuration) {
this.junitPlatformLauncher.extendsFrom(configuration);
}
}

@ -95,12 +95,6 @@ class SpringBootAotPluginIntegrationTests {
assertThat(output).contains("org.jboss.logging" + File.separatorChar + "jboss-logging");
}
@TestTemplate
void processAotIsSkippedWhenProjectHasNoMainSource() {
assertThat(this.gradleBuild.build("processAot").task(":processAot").getOutcome())
.isEqualTo(TaskOutcome.NO_SOURCE);
}
@TestTemplate
void processAotRunsWhenProjectHasMainSource() throws IOException {
writeMainClass("org.springframework.boot", "SpringApplicationAotProcessor");

@ -4,12 +4,28 @@ plugins {
id 'java'
}
repositories {
mavenCentral()
maven { url 'file:repository' }
}
configurations.all {
resolutionStrategy {
eachDependency {
if (it.requested.group == 'org.springframework.boot') {
it.useVersion project.bootVersion
}
}
}
}
dependencies {
implementation project(":library")
}
task('processTestAotClasspath') {
dependsOn configurations.processTestAotClasspath
doFirst {
tasks.findByName('processTestAot').classpath.files.each { println it }
configurations.processTestAotClasspath.files.each { println it }
}
}

@ -6,6 +6,17 @@ plugins {
repositories {
mavenCentral()
maven { url 'file:repository' }
}
configurations.all {
resolutionStrategy {
eachDependency {
if (it.requested.group == 'org.springframework.boot') {
it.useVersion project.bootVersion
}
}
}
}
dependencies {
@ -13,7 +24,8 @@ dependencies {
}
task('processTestAotClasspath') {
dependsOn configurations.processTestAotClasspath
doFirst {
tasks.findByName('processTestAot').classpath.files.each { println it }
configurations.processTestAotClasspath.files.each { println it }
}
}

@ -22,6 +22,11 @@
<artifactId>spring-boot-starter</artifactId>
<version>TEST-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.9.1</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

Loading…
Cancel
Save