Skip to content

Commit 877d729

Browse files
committed
Add support for invoking AOT in the Gradle plugin
1 parent 6c607ac commit 877d729

File tree

5 files changed

+176
-2
lines changed

5 files changed

+176
-2
lines changed

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ dependencies {
2222
implementation("org.apache.commons:commons-compress")
2323
implementation("org.springframework:spring-core")
2424

25+
optional("org.graalvm.buildtools:native-gradle-plugin:0.9.11")
2526
optional("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") {
2627
exclude(group: "commons-logging", module: "commons-logging")
2728
}

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/dsl/SpringBootExtension.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.gradle.plugin;
18+
19+
import java.util.List;
20+
21+
import org.graalvm.buildtools.gradle.NativeImagePlugin;
22+
import org.graalvm.buildtools.gradle.dsl.GraalVMExtension;
23+
import org.graalvm.buildtools.gradle.tasks.BuildNativeImageTask;
24+
import org.gradle.api.Action;
25+
import org.gradle.api.Plugin;
26+
import org.gradle.api.Project;
27+
import org.gradle.api.artifacts.Configuration;
28+
import org.gradle.api.artifacts.ConfigurationContainer;
29+
import org.gradle.api.plugins.JavaPlugin;
30+
import org.gradle.api.plugins.JavaPluginExtension;
31+
import org.gradle.api.tasks.SourceSet;
32+
import org.gradle.api.tasks.SourceSetContainer;
33+
import org.gradle.api.tasks.TaskProvider;
34+
35+
import org.springframework.boot.gradle.tasks.aot.GenerateAotSources;
36+
37+
/**
38+
* {@link Action} that is executed in response to the {@link NativeImagePlugin} being
39+
* applied.
40+
*
41+
* @author Andy Wilkinson
42+
*/
43+
class NativeImagePluginAction implements PluginApplicationAction {
44+
45+
@Override
46+
public Class<? extends Plugin<? extends Project>> getPluginClass()
47+
throws ClassNotFoundException, NoClassDefFoundError {
48+
return NativeImagePlugin.class;
49+
}
50+
51+
@Override
52+
public void execute(Project project) {
53+
project.getPlugins().withType(JavaPlugin.class).all((plugin) -> {
54+
SourceSet aotSourceSet = configureAotSourceSet(project);
55+
registerGenerateAotSourcesTask(project, aotSourceSet);
56+
project.getTasks().named(NativeImagePlugin.NATIVE_COMPILE_TASK_NAME, BuildNativeImageTask.class,
57+
(nativeCompile) -> nativeCompile.getOptions().get().classpath(aotSourceSet.getOutput()));
58+
});
59+
GraalVMExtension graalVmExtension = project.getExtensions().getByType(GraalVMExtension.class);
60+
graalVmExtension.getToolchainDetection().set(false);
61+
}
62+
63+
private SourceSet configureAotSourceSet(Project project) {
64+
JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);
65+
SourceSetContainer sourceSets = javaPluginExtension.getSourceSets();
66+
SourceSet main = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
67+
SourceSet aotSourceSet = sourceSets.create("aot", (aot) -> {
68+
aot.getJava().setSrcDirs(List.of("build/generated/aotSources"));
69+
aot.getResources().setSrcDirs(List.of("build/generated/aotResources"));
70+
aot.setCompileClasspath(aot.getCompileClasspath().plus(main.getOutput()));
71+
main.setRuntimeClasspath(main.getRuntimeClasspath().plus(aot.getOutput()));
72+
ConfigurationContainer configurations = project.getConfigurations();
73+
Configuration aotImplementation = configurations.getByName(aot.getImplementationConfigurationName());
74+
aotImplementation.extendsFrom(configurations.getByName(main.getImplementationConfigurationName()));
75+
aotImplementation.extendsFrom(configurations.getByName(main.getRuntimeOnlyConfigurationName()));
76+
});
77+
return aotSourceSet;
78+
}
79+
80+
private void registerGenerateAotSourcesTask(Project project, SourceSet aotSourceSet) {
81+
TaskProvider<ResolveMainClassName> resolveMainClassName = project.getTasks()
82+
.named(SpringBootPlugin.RESOLVE_MAIN_CLASS_NAME_TASK_NAME, ResolveMainClassName.class);
83+
TaskProvider<GenerateAotSources> generateAotSources = project.getTasks().register("generateAotSources",
84+
GenerateAotSources.class, (task) -> {
85+
task.getApplicationClass().set(resolveMainClassName.flatMap((thing) -> thing.readMainClassName()));
86+
task.setClasspath(aotSourceSet.getCompileClasspath());
87+
task.getSourcesDir().set(aotSourceSet.getJava().getSrcDirs().iterator().next());
88+
task.getResourcesDir().set(aotSourceSet.getResources().getSrcDirs().iterator().next());
89+
});
90+
project.getTasks().getByName(aotSourceSet.getCompileJavaTaskName(),
91+
(compile) -> compile.dependsOn(generateAotSources));
92+
project.getTasks().getByName(aotSourceSet.getProcessResourcesTaskName(),
93+
(processResources) -> processResources.dependsOn(generateAotSources));
94+
}
95+
96+
}

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ private void registerPluginActions(Project project, Configuration bootArchives)
126126
project.getArtifacts());
127127
List<PluginApplicationAction> actions = Arrays.asList(new JavaPluginAction(singlePublishedArtifact),
128128
new WarPluginAction(singlePublishedArtifact), new DependencyManagementPluginAction(),
129-
new ApplicationPluginAction(), new KotlinPluginAction());
129+
new ApplicationPluginAction(), new KotlinPluginAction(), new NativeImagePluginAction());
130130
for (PluginApplicationAction action : actions) {
131131
withPluginClassOfAction(action,
132132
(pluginClass) -> project.getPlugins().withType(pluginClass, (plugin) -> action.execute(project)));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.gradle.tasks.aot;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import org.gradle.api.file.DirectoryProperty;
23+
import org.gradle.api.provider.Property;
24+
import org.gradle.api.tasks.Input;
25+
import org.gradle.api.tasks.JavaExec;
26+
import org.gradle.api.tasks.OutputDirectory;
27+
import org.gradle.api.tasks.TaskAction;
28+
29+
/**
30+
* Custom {@link JavaExec} task for generating sources ahead of time.
31+
*
32+
* @author Andy Wilkinson
33+
* @since 3.0
34+
*/
35+
public class GenerateAotSources extends JavaExec {
36+
37+
private final Property<String> applicationClass;
38+
39+
private final DirectoryProperty sourcesDir;
40+
41+
private final DirectoryProperty resourcesDir;
42+
43+
public GenerateAotSources() {
44+
this.applicationClass = getProject().getObjects().property(String.class);
45+
this.sourcesDir = getProject().getObjects().directoryProperty();
46+
this.resourcesDir = getProject().getObjects().directoryProperty();
47+
getMainClass().set("org.springframework.boot.AotProcessor");
48+
}
49+
50+
@Input
51+
public Property<String> getApplicationClass() {
52+
return this.applicationClass;
53+
}
54+
55+
@OutputDirectory
56+
public DirectoryProperty getSourcesDir() {
57+
return this.sourcesDir;
58+
}
59+
60+
@OutputDirectory
61+
public DirectoryProperty getResourcesDir() {
62+
return this.resourcesDir;
63+
}
64+
65+
@Override
66+
@TaskAction
67+
public void exec() {
68+
List<String> args = new ArrayList<>();
69+
args.add(this.applicationClass.get());
70+
args.add(this.sourcesDir.getAsFile().get().getAbsolutePath());
71+
args.add(this.resourcesDir.getAsFile().get().getAbsolutePath());
72+
args.addAll(super.getArgs());
73+
this.setArgs(args);
74+
super.exec();
75+
}
76+
77+
}

0 commit comments

Comments
 (0)