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 d73bcc0cbb8..2b2028ea2ca 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 7526220cb42..612479175d5 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 877fc0ec242..cc277d5c42e 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 00000000000..a668b9c72f9 --- /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' +