From 23ae91b008d456775e91b9f3d508688e4da9fe85 Mon Sep 17 00:00:00 2001 From: Scott Frederick Date: Tue, 2 May 2023 15:11:49 -0500 Subject: [PATCH] Add native image manifest entry A manifest entry `Spring-Boot-Native-Processed: true` is added to the jar manifest by the Maven or Gradle plugin when the jar has been built for use in a native image. With the Gradle plugin, this is done in reaction to the GraalVM Native Image Plugin being applied to the project. With the Maven plugin, this is done when the `native` profile is applied to the build. --- .../spring-boot-starter-parent/build.gradle | 11 +++++++++++ .../boot/gradle/plugin/NativeImagePluginAction.java | 13 ++++++++++--- .../NativeImagePluginActionIntegrationTests.java | 12 ++++++++++++ ...grationTests-nativeEntryIsAddedToManifest.gradle | 8 ++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests-nativeEntryIsAddedToManifest.gradle diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/build.gradle b/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/build.gradle index d73bcc0cbb..2b2028ea2c 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/build.gradle +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/build.gradle @@ -233,6 +233,17 @@ publishing.publications.withType(MavenPublication) { build { pluginManagement { plugins { + plugin { + delegate.groupId('org.apache.maven.plugins') + delegate.artifactId('maven-jar-plugin') + configuration { + archive { + manifestEntries { + delegate.'Spring-Boot-Native-Processed'("true") + } + } + } + } plugin { delegate.groupId('org.springframework.boot') delegate.artifactId('spring-boot-maven-plugin') 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 index 7526220cb4..612479175d 100644 --- 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 @@ -59,10 +59,11 @@ class NativeImagePluginAction implements PluginApplicationAction { SourceSetContainer sourceSets = javaPluginExtension.getSourceSets(); GraalVMExtension graalVmExtension = configureGraalVmExtension(project); configureMainNativeBinaryClasspath(project, sourceSets, graalVmExtension); - configureTestNativeBinaryClasspath(project, sourceSets, graalVmExtension); + configureTestNativeBinaryClasspath(sourceSets, graalVmExtension); configureGraalVmReachabilityExtension(graalVmExtension); copyReachabilityMetadataToBootJar(project); configureBootBuildImageToProduceANativeImage(project); + configureJarManifestNativeAttribute(project); }); } @@ -85,8 +86,7 @@ class NativeImagePluginAction implements PluginApplicationAction { return !SpringBootPlugin.DEVELOPMENT_ONLY_CONFIGURATION_NAME.equals(configuration.getName()); } - private void configureTestNativeBinaryClasspath(Project project, SourceSetContainer sourceSets, - GraalVMExtension graalVmExtension) { + private void configureTestNativeBinaryClasspath(SourceSetContainer sourceSets, GraalVMExtension graalVmExtension) { FileCollection runtimeClasspath = sourceSets.getByName(SpringBootAotPlugin.AOT_TEST_SOURCE_SET_NAME) .getRuntimeClasspath(); graalVmExtension.getBinaries().getByName(NativeImagePlugin.NATIVE_TEST_EXTENSION).classpath(runtimeClasspath); @@ -119,4 +119,11 @@ class NativeImagePluginAction implements PluginApplicationAction { }); } + private void configureJarManifestNativeAttribute(Project project) { + project.getTasks() + .named(SpringBootPlugin.BOOT_JAR_TASK_NAME, BootJar.class) + .configure((bootJar) -> bootJar + .manifest(((manifest) -> manifest.getAttributes().put("Spring-Boot-Native-Processed", true)))); + } + } 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 877fc0ec24..cc277d5c42 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 @@ -25,6 +25,7 @@ import java.util.Enumeration; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.jar.Manifest; import org.gradle.testkit.runner.BuildResult; import org.gradle.testkit.runner.TaskOutcome; @@ -115,6 +116,17 @@ class NativeImagePluginActionIntegrationTests { projectPath("build/resources/aotTest"), projectPath("build/generated/aotTestClasses")); } + @TestTemplate + void nativeEntryIsAddedToManifest() throws IOException { + writeDummySpringApplicationAotProcessorMainClass(); + BuildResult result = this.gradleBuild.build("bootJar"); + assertThat(result.task(":bootJar").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + File buildLibs = new File(this.gradleBuild.getProjectDir(), "build/libs"); + JarFile jarFile = new JarFile(new File(buildLibs, this.gradleBuild.getProjectDir().getName() + ".jar")); + Manifest manifest = jarFile.getManifest(); + assertThat(manifest.getMainAttributes().getValue("Spring-Boot-Native-Processed")).isEqualTo("true"); + } + private String projectPath(String path) { try { return new File(this.gradleBuild.getProjectDir(), path).getCanonicalPath(); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests-nativeEntryIsAddedToManifest.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests-nativeEntryIsAddedToManifest.gradle new file mode 100644 index 0000000000..a668b9c72f --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests-nativeEntryIsAddedToManifest.gradle @@ -0,0 +1,8 @@ +plugins { + id 'java' + id 'org.springframework.boot' + id 'org.springframework.boot.aot' +} + +apply plugin: 'org.graalvm.buildtools.native' +