From 9378fc47a7a1e0e3105bc628510760730e6fd4a2 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 8 Feb 2023 10:52:32 +0000 Subject: [PATCH] Set implementation name and version in Gradle-built archives Closes gh-34059 --- .../tasks/bundling/BootArchiveSupport.java | 13 ++++++- .../boot/gradle/tasks/bundling/BootJar.java | 11 +++++- .../boot/gradle/tasks/bundling/BootWar.java | 11 +++++- .../bundling/AbstractBootArchiveTests.java | 38 ++++++++++++++++++- 4 files changed, 66 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchiveSupport.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchiveSupport.java index 7335090fa5..800e826a89 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchiveSupport.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchiveSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 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. @@ -54,6 +54,8 @@ class BootArchiveSupport { private static final byte[] ZIP_FILE_HEADER = new byte[] { 'P', 'K', 3, 4 }; + private static final String UNSPECIFIED_VERSION = "unspecified"; + private static final Set DEFAULT_LAUNCHER_CLASSES; static { @@ -85,7 +87,7 @@ class BootArchiveSupport { } void configureManifest(Manifest manifest, String mainClass, String classes, String lib, String classPathIndex, - String layersIndex, String jdkVersion) { + String layersIndex, String jdkVersion, String implementationName, Object implementationVersion) { Attributes attributes = manifest.getAttributes(); attributes.putIfAbsent("Main-Class", this.loaderMainClass); attributes.putIfAbsent("Start-Class", mainClass); @@ -99,6 +101,13 @@ class BootArchiveSupport { attributes.putIfAbsent("Spring-Boot-Layers-Index", layersIndex); } attributes.putIfAbsent("Build-Jdk-Spec", jdkVersion); + attributes.putIfAbsent("Implementation-Name", implementationName); + if (implementationVersion != null) { + String versionString = implementationVersion.toString(); + if (!UNSPECIFIED_VERSION.equals(versionString)) { + attributes.putIfAbsent("Implementation-Version", versionString); + } + } } private String determineSpringBootVersion() { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java index cbbb07ec30..b9dfd52a4d 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 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. @@ -29,6 +29,7 @@ import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileCopyDetails; import org.gradle.api.file.FileTreeElement; import org.gradle.api.internal.file.copy.CopyAction; +import org.gradle.api.provider.Provider; import org.gradle.api.specs.Spec; import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.Nested; @@ -65,6 +66,10 @@ public abstract class BootJar extends Jar implements BootArchive { private final LayeredSpec layered; + private final Provider projectName; + + private final Provider projectVersion; + private FileCollection classpath; /** @@ -85,6 +90,8 @@ public abstract class BootJar extends Jar implements BootArchive { } }); }); + this.projectName = project.provider(project::getName); + this.projectVersion = project.provider(project::getVersion); } private void configureBootInfSpec(CopySpec bootInfSpec) { @@ -120,7 +127,7 @@ public abstract class BootJar extends Jar implements BootArchive { public void copy() { this.support.configureManifest(getManifest(), getMainClass().get(), CLASSES_DIRECTORY, LIB_DIRECTORY, CLASSPATH_INDEX, (isLayeredDisabled()) ? null : LAYERS_INDEX, - this.getTargetJavaVersion().get().getMajorVersion()); + this.getTargetJavaVersion().get().getMajorVersion(), this.projectName.get(), this.projectVersion.get()); super.copy(); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java index 0ad92c183b..76b1f75601 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 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. @@ -28,6 +28,7 @@ import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileCopyDetails; import org.gradle.api.file.FileTreeElement; import org.gradle.api.internal.file.copy.CopyAction; +import org.gradle.api.provider.Provider; import org.gradle.api.specs.Spec; import org.gradle.api.tasks.Classpath; import org.gradle.api.tasks.Internal; @@ -65,6 +66,10 @@ public abstract class BootWar extends War implements BootArchive { private final LayeredSpec layered; + private final Provider projectName; + + private final Provider projectVersion; + private FileCollection providedClasspath; /** @@ -85,6 +90,8 @@ public abstract class BootWar extends War implements BootArchive { } }); }); + this.projectName = project.provider(project::getName); + this.projectVersion = project.provider(project::getVersion); } private Object getProvidedLibFiles() { @@ -95,7 +102,7 @@ public abstract class BootWar extends War implements BootArchive { public void copy() { this.support.configureManifest(getManifest(), getMainClass().get(), CLASSES_DIRECTORY, LIB_DIRECTORY, CLASSPATH_INDEX, (isLayeredDisabled()) ? null : LAYERS_INDEX, - this.getTargetJavaVersion().get().getMajorVersion()); + this.getTargetJavaVersion().get().getMajorVersion(), this.projectName.get(), this.projectVersion.get()); super.copy(); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java index 4caa3fc3e3..96be257ba0 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 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. @@ -132,6 +132,42 @@ abstract class AbstractBootArchiveTests { .isEqualTo(this.classesPath); assertThat(jarFile.getManifest().getMainAttributes().getValue("Spring-Boot-Lib")).isEqualTo(this.libPath); assertThat(jarFile.getManifest().getMainAttributes().getValue("Spring-Boot-Version")).isNotNull(); + assertThat(jarFile.getManifest().getMainAttributes().getValue("Implementation-Name")) + .isEqualTo(this.project.getName()); + assertThat(jarFile.getManifest().getMainAttributes().getValue("Implementation-Version")).isNull(); + } + } + + @Test + void whenImplementationNameIsCustomizedItShouldAppearInArchiveManifest() throws IOException { + this.task.getMainClass().set("com.example.Main"); + this.task.getManifest().getAttributes().put("Implementation-Name", "Customized"); + executeTask(); + try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) { + assertThat(jarFile.getManifest().getMainAttributes().getValue("Implementation-Name")) + .isEqualTo("Customized"); + } + } + + @Test + void whenProjectVersionIsSetThenImplementationVersionShouldAppearInArchiveManifest() throws IOException { + this.project.setVersion("1.0.0"); + this.task.getMainClass().set("com.example.Main"); + executeTask(); + try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) { + assertThat(jarFile.getManifest().getMainAttributes().getValue("Implementation-Version")).isEqualTo("1.0.0"); + } + } + + @Test + void whenImplementationVersionIsCustomizedItShouldAppearInArchiveManifest() throws IOException { + this.project.setVersion("1.0.0"); + this.task.getMainClass().set("com.example.Main"); + this.task.getManifest().getAttributes().put("Implementation-Version", "Customized"); + executeTask(); + try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) { + assertThat(jarFile.getManifest().getMainAttributes().getValue("Implementation-Version")) + .isEqualTo("Customized"); } }