diff --git a/spring-boot-project/spring-boot-parent/build.gradle b/spring-boot-project/spring-boot-parent/build.gradle index 11b19a3a5d..2ee2f72296 100644 --- a/spring-boot-project/spring-boot-parent/build.gradle +++ b/spring-boot-project/spring-boot-parent/build.gradle @@ -126,6 +126,13 @@ bom { ] } } + library("Native Gradle Plugin", "0.9.11") { + group("org.graalvm.buildtools") { + modules = [ + "native-gradle-plugin" + ] + } + } library("Plexus Build API", "0.0.7") { group("org.sonatype.plexus") { modules = [ diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/build.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/build.gradle index 9160451166..5bb7868a98 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/build.gradle +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/build.gradle @@ -7,7 +7,7 @@ plugins { id "org.springframework.boot.optional-dependencies" } -description = "Spring Boot Gradle Plugin" +description = "Spring Boot Gradle Plugins" configurations { documentation @@ -22,6 +22,7 @@ dependencies { implementation("org.apache.commons:commons-compress") implementation("org.springframework:spring-core") + optional("org.graalvm.buildtools:native-gradle-plugin") optional("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") { exclude(group: "commons-logging", module: "commons-logging") } @@ -44,6 +45,12 @@ gradlePlugin { description = "Spring Boot Gradle Plugin" implementationClass = "org.springframework.boot.gradle.plugin.SpringBootPlugin" } + springBootAotPlugin { + id = "org.springframework.boot.aot" + displayName = "Spring Boot AOT Gradle Plugin" + description = "Spring Boot AOT Gradle Plugin" + implementationClass = "org.springframework.boot.gradle.plugin.SpringBootAotPlugin" + } } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/index.adoc b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/index.adoc index 0558da915d..94f10173b9 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/index.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/index.adoc @@ -39,6 +39,7 @@ v{gradle-project-version} :buildpacks-reference: https://buildpacks.io/docs :paketo-reference: https://paketo.io/docs :paketo-java-reference: {paketo-reference}/buildpacks/language-family-buildpacks/java +:nbt-gradle-plugin: https://graalvm.github.io/native-build-tools/latest/gradle-plugin.html diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/reacting.adoc b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/reacting.adoc index 673f54a768..87a023f5d0 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/reacting.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/reacting.adoc @@ -63,3 +63,16 @@ When Gradle's {application-plugin}[`application` plugin] is applied to a project 5. Configures the `bootJar` task to use the `mainClassName` property as a convention for the `Start-Class` entry in its manifest. 6. Configures the `bootWar` task to use the `mainClassName` property as a convention for the `Start-Class` entry in its manifest. + + +[[reacting-to-other-plugins.nbt]] +== Reacting to the GraalVM Native Image Plugin +When the {nbt-gradle-plugin}[GraalVM Native Image plugin] is applied to a project, the Spring Boot plugin: + +. Applies the `org.springframework.boot.aot` plugin that: +.. Registers a `GenerateAotSources` task named `generateAotSources` that will generate AOT-optimized source code for the application. +.. Configures the Java compilation and process resources tasks for the `aot` source set to depend upon `generateAotSources`. +. Adds the output of the `aot` source set to the classpath of the `nativeCompile` task. +. Configures the GraalVM extension to disable Toolchain detection. + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/NativeImagePluginAction.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/NativeImagePluginAction.java new file mode 100644 index 0000000000..3cfbc324f0 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/NativeImagePluginAction.java @@ -0,0 +1,58 @@ +/* + * 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.gradle.plugin; + +import org.graalvm.buildtools.gradle.NativeImagePlugin; +import org.graalvm.buildtools.gradle.dsl.GraalVMExtension; +import org.graalvm.buildtools.gradle.tasks.BuildNativeImageTask; +import org.gradle.api.Action; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.plugins.JavaPluginExtension; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetContainer; + +/** + * {@link Action} that is executed in response to the {@link NativeImagePlugin} being + * applied. + * + * @author Andy Wilkinson + */ +class NativeImagePluginAction implements PluginApplicationAction { + + @Override + public Class> getPluginClass() + throws ClassNotFoundException, NoClassDefFoundError { + return NativeImagePlugin.class; + } + + @Override + public void execute(Project project) { + project.getPlugins().apply(SpringBootAotPlugin.class); + project.getPlugins().withType(JavaPlugin.class).all((plugin) -> { + JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class); + SourceSetContainer sourceSets = javaPluginExtension.getSourceSets(); + SourceSet aotSourceSet = sourceSets.getByName(SpringBootAotPlugin.AOT_SOURCE_SET_NAME); + project.getTasks().named(NativeImagePlugin.NATIVE_COMPILE_TASK_NAME, BuildNativeImageTask.class, + (nativeCompile) -> nativeCompile.getOptions().get().classpath(aotSourceSet.getOutput())); + }); + GraalVMExtension graalVmExtension = project.getExtensions().getByType(GraalVMExtension.class); + graalVmExtension.getToolchainDetection().set(false); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootAotPlugin.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootAotPlugin.java new file mode 100644 index 0000000000..e384e0bf5d --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootAotPlugin.java @@ -0,0 +1,98 @@ +/* + * 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.gradle.plugin; + +import java.util.List; + +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.ConfigurationContainer; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.plugins.JavaPluginExtension; +import org.gradle.api.plugins.PluginContainer; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetContainer; +import org.gradle.api.tasks.TaskProvider; + +import org.springframework.boot.gradle.tasks.aot.GenerateAotSources; + +/** + * Gradle plugin for Spring Boot AOT. + * + * @author Andy Wilkinson + * @since 3.0.0 + */ +public class SpringBootAotPlugin implements Plugin { + + /** + * Name of the {@code aot} {@link SourceSet source set}. + */ + public static final String AOT_SOURCE_SET_NAME = "aot"; + + /** + * Name of the default {@link GenerateAotSources} task. + */ + public static final String GENERATE_AOT_SOURCES_TASK_NAME = "generateAotSources"; + + @Override + public void apply(Project project) { + PluginContainer plugins = project.getPlugins(); + plugins.withType(JavaPlugin.class).all((javaPlugin) -> { + plugins.withType(SpringBootPlugin.class).all((bootPlugin) -> { + SourceSet aotSourceSet = configureAotSourceSet(project); + registerGenerateAotSourcesTask(project, aotSourceSet); + }); + }); + } + + private SourceSet configureAotSourceSet(Project project) { + JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class); + SourceSetContainer sourceSets = javaPluginExtension.getSourceSets(); + SourceSet main = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME); + SourceSet aotSourceSet = sourceSets.create(AOT_SOURCE_SET_NAME, (aot) -> { + aot.getJava().setSrcDirs(List.of("build/generated/aotSources")); + aot.getResources().setSrcDirs(List.of("build/generated/aotResources")); + aot.setCompileClasspath(aot.getCompileClasspath().plus(main.getOutput())); + main.setRuntimeClasspath(main.getRuntimeClasspath().plus(aot.getOutput())); + ConfigurationContainer configurations = project.getConfigurations(); + Configuration aotImplementation = configurations.getByName(aot.getImplementationConfigurationName()); + aotImplementation.extendsFrom(configurations.getByName(main.getImplementationConfigurationName())); + aotImplementation.extendsFrom(configurations.getByName(main.getRuntimeOnlyConfigurationName())); + }); + return aotSourceSet; + } + + private void registerGenerateAotSourcesTask(Project project, SourceSet aotSourceSet) { + TaskProvider resolveMainClassName = project.getTasks() + .named(SpringBootPlugin.RESOLVE_MAIN_CLASS_NAME_TASK_NAME, ResolveMainClassName.class); + TaskProvider generateAotSources = project.getTasks() + .register(GENERATE_AOT_SOURCES_TASK_NAME, GenerateAotSources.class, (task) -> { + task.getApplicationClass().set(resolveMainClassName.flatMap((thing) -> thing.readMainClassName())); + task.setClasspath(aotSourceSet.getCompileClasspath()); + task.getSourcesDir().set(aotSourceSet.getJava().getSrcDirs().iterator().next()); + task.getResourcesDir().set(aotSourceSet.getResources().getSrcDirs().iterator().next()); + task.getGroupId().set(project.provider(() -> String.valueOf(project.getGroup()))); + task.getArtifactId().set(project.provider(() -> project.getName())); + }); + project.getTasks().getByName(aotSourceSet.getCompileJavaTaskName(), + (compile) -> compile.dependsOn(generateAotSources)); + project.getTasks().getByName(aotSourceSet.getProcessResourcesTaskName(), + (processResources) -> processResources.dependsOn(generateAotSources)); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java index 7f0365a0eb..a564f9b542 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java @@ -126,7 +126,7 @@ public class SpringBootPlugin implements Plugin { project.getArtifacts()); List actions = Arrays.asList(new JavaPluginAction(singlePublishedArtifact), new WarPluginAction(singlePublishedArtifact), new DependencyManagementPluginAction(), - new ApplicationPluginAction(), new KotlinPluginAction()); + new ApplicationPluginAction(), new KotlinPluginAction(), new NativeImagePluginAction()); for (PluginApplicationAction action : actions) { withPluginClassOfAction(action, (pluginClass) -> project.getPlugins().withType(pluginClass, (plugin) -> action.execute(project))); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/GenerateAotSources.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/GenerateAotSources.java new file mode 100644 index 0000000000..3ec84bbd17 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/GenerateAotSources.java @@ -0,0 +1,95 @@ +/* + * 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.gradle.tasks.aot; + +import java.util.ArrayList; +import java.util.List; + +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.CacheableTask; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.JavaExec; +import org.gradle.api.tasks.OutputDirectory; +import org.gradle.api.tasks.TaskAction; + +/** + * Custom {@link JavaExec} task for generating sources ahead of time. + * + * @author Andy Wilkinson + * @since 3.0 + */ +@CacheableTask +public class GenerateAotSources extends JavaExec { + + private final Property applicationClass; + + private final DirectoryProperty sourcesDir; + + private final DirectoryProperty resourcesDir; + + private final Property groupId; + + private final Property artifactId; + + public GenerateAotSources() { + this.applicationClass = getProject().getObjects().property(String.class); + this.sourcesDir = getProject().getObjects().directoryProperty(); + this.resourcesDir = getProject().getObjects().directoryProperty(); + this.groupId = getProject().getObjects().property(String.class); + this.artifactId = getProject().getObjects().property(String.class); + getMainClass().set("org.springframework.boot.AotProcessor"); + } + + @Input + public Property getApplicationClass() { + return this.applicationClass; + } + + @Input + public Property getGroupId() { + return this.groupId; + } + + @Input + public Property getArtifactId() { + return this.artifactId; + } + + @OutputDirectory + public DirectoryProperty getSourcesDir() { + return this.sourcesDir; + } + + @OutputDirectory + public DirectoryProperty getResourcesDir() { + return this.resourcesDir; + } + + @Override + @TaskAction + public void exec() { + List args = new ArrayList<>(); + args.add(this.applicationClass.get()); + args.add(this.sourcesDir.getAsFile().get().getAbsolutePath()); + args.add(this.resourcesDir.getAsFile().get().getAbsolutePath()); + args.addAll(super.getArgs()); + this.setArgs(args); + super.exec(); + } + +} 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 new file mode 100644 index 0000000000..2a3d685443 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests.java @@ -0,0 +1,42 @@ +/* + * 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.gradle.plugin; + +import org.junit.jupiter.api.TestTemplate; + +import org.springframework.boot.gradle.junit.GradleCompatibility; +import org.springframework.boot.testsupport.gradle.testkit.GradleBuild; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link NativeImagePluginAction}. + * + * @author Andy Wilkinson + */ +@GradleCompatibility(configurationCache = true) +class NativeImagePluginActionIntegrationTests { + + GradleBuild gradleBuild; + + @TestTemplate + void applyingNativeImagePluginAppliesAotPlugin() { + assertThat(this.gradleBuild.build("aotPluginApplied").getOutput()) + .contains("org.springframework.boot.aot applied = true"); + } + +} 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 new file mode 100644 index 0000000000..53baad8794 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests.java @@ -0,0 +1,48 @@ +/* + * 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.gradle.plugin; + +import org.junit.jupiter.api.TestTemplate; + +import org.springframework.boot.gradle.junit.GradleCompatibility; +import org.springframework.boot.testsupport.gradle.testkit.GradleBuild; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link SpringBootAotPlugin}. + * + * @author Andy Wilkinson + */ +@GradleCompatibility +class SpringBootAotPluginIntegrationTests { + + GradleBuild gradleBuild; + + @TestTemplate + void noGenerateAotSourcesTaskWithoutAotPluginApplied() { + assertThat(this.gradleBuild.build("taskExists", "-PtaskName=generateAotSources").getOutput()) + .contains("generateAotSources exists = false"); + } + + @TestTemplate + void applyingAotPluginCreatesGenerateAotSourcesTask() { + assertThat(this.gradleBuild.build("taskExists", "-PtaskName=generateAotSources").getOutput()) + .contains("generateAotSources exists = true"); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests.java index 85a0865d8d..f58042d5d4 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests.java @@ -97,10 +97,10 @@ class BootRunIntegrationTests { BuildResult result = this.gradleBuild.build("bootRun"); assertThat(result.task(":bootRun").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_13)) { - assertThat(result.getOutput()).contains("1. -XX:TieredStopAtLevel=1"); + assertThat(result.getOutput()).contains("-XX:TieredStopAtLevel=1"); } else { - assertThat(result.getOutput()).contains("1. -Xverify:none").contains("2. -XX:TieredStopAtLevel=1"); + assertThat(result.getOutput()).contains("-Xverify:none").contains("-XX:TieredStopAtLevel=1"); } } @@ -118,12 +118,12 @@ class BootRunIntegrationTests { BuildResult result = this.gradleBuild.build("bootRun"); assertThat(result.task(":bootRun").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_13)) { - assertThat(result.getOutput()).contains("1. -Dcom.bar=baz").contains("2. -Dcom.foo=bar") - .contains("3. -XX:TieredStopAtLevel=1"); + assertThat(result.getOutput()).contains("-Dcom.bar=baz").contains("-Dcom.foo=bar") + .contains("-XX:TieredStopAtLevel=1"); } else { - assertThat(result.getOutput()).contains("1. -Dcom.bar=baz").contains("2. -Dcom.foo=bar") - .contains("3. -Xverify:none").contains("4. -XX:TieredStopAtLevel=1"); + assertThat(result.getOutput()).contains("-Dcom.bar=baz").contains("-Dcom.foo=bar").contains("-Xverify:none") + .contains("-XX:TieredStopAtLevel=1"); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests-applyingNativeImagePluginAppliesAotPlugin.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests-applyingNativeImagePluginAppliesAotPlugin.gradle new file mode 100644 index 0000000000..85ddb1ea52 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests-applyingNativeImagePluginAppliesAotPlugin.gradle @@ -0,0 +1,11 @@ +plugins { + id 'org.springframework.boot' version '{version}' +} + +apply plugin: 'org.graalvm.buildtools.native' + +task('aotPluginApplied') { + doFirst { + println "org.springframework.boot.aot applied = ${plugins.hasPlugin('org.springframework.boot.aot')}" + } +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-applyingAotPluginCreatesGenerateAotSourcesTask.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-applyingAotPluginCreatesGenerateAotSourcesTask.gradle new file mode 100644 index 0000000000..9bc1246d25 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-applyingAotPluginCreatesGenerateAotSourcesTask.gradle @@ -0,0 +1,11 @@ +plugins { + id 'org.springframework.boot' + id 'org.springframework.boot.aot' + id 'java' +} + +task('taskExists') { + doFirst { + println "${taskName} exists = ${tasks.findByName(taskName) != null}" + } +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-noGenerateAotSourcesTaskWithoutAotPluginApplied.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-noGenerateAotSourcesTaskWithoutAotPluginApplied.gradle new file mode 100644 index 0000000000..8870522dae --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-noGenerateAotSourcesTaskWithoutAotPluginApplied.gradle @@ -0,0 +1,10 @@ +plugins { + id 'org.springframework.boot' + id 'java' +} + +task('taskExists') { + doFirst { + println "${taskName} exists = ${tasks.findByName(taskName) != null}" + } +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-test-support/build.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-test-support/build.gradle index e3cb7071a5..d3df269b1b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-test-support/build.gradle +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-test-support/build.gradle @@ -12,6 +12,7 @@ dependencies { implementation(project(":spring-boot-project:spring-boot-tools:spring-boot-buildpack-platform")) implementation(project(":spring-boot-project:spring-boot-tools:spring-boot-loader-tools")) implementation("io.spring.gradle:dependency-management-plugin") + implementation("org.graalvm.buildtools:native-gradle-plugin") implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") implementation("org.jetbrains.kotlin:kotlin-compiler-embeddable:$kotlinVersion") implementation("org.jetbrains.kotlin:kotlin-compiler-runner:$kotlinVersion") diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-test-support/src/main/java/org/springframework/boot/testsupport/gradle/testkit/GradleBuild.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-test-support/src/main/java/org/springframework/boot/testsupport/gradle/testkit/GradleBuild.java index 7268df47aa..768a5ebc32 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-test-support/src/main/java/org/springframework/boot/testsupport/gradle/testkit/GradleBuild.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-test-support/src/main/java/org/springframework/boot/testsupport/gradle/testkit/GradleBuild.java @@ -124,7 +124,9 @@ public class GradleBuild { new File(pathOfJarContaining(Versioned.class)), new File(pathOfJarContaining(ParameterNamesModule.class)), new File(pathOfJarContaining(JsonView.class)), new File(pathOfJarContaining(Platform.class)), - new File(pathOfJarContaining(Toml.class)), new File(pathOfJarContaining(Lexer.class))); + new File(pathOfJarContaining(Toml.class)), new File(pathOfJarContaining(Lexer.class)), + new File(pathOfJarContaining("org.graalvm.buildtools.gradle.NativeImagePlugin")), + new File(pathOfJarContaining("org.graalvm.reachability.JvmReachabilityMetadataRepository"))); } private String pathOfJarContaining(String className) {