From ec8fb614f707e5f3bf8f7690e8384e1552a24570 Mon Sep 17 00:00:00 2001 From: Hendrig Sellik Date: Sat, 9 Mar 2019 12:00:59 +0100 Subject: [PATCH] Determine Spring Boot version correctly when using module path In Java 9, a package may return null for its implementation version even when the manifest attribute specifying the version is present in the jar from which the package was loaded. This commit updates SpringBootVersion to fall back to accessing the jar and its manifest attributes directly when the implementation version of its package is null. See gh-16182 --- .../boot/SpringBootVersion.java | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringBootVersion.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringBootVersion.java index 2e6ea56a659..9eea37bd887 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringBootVersion.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringBootVersion.java @@ -16,6 +16,14 @@ package org.springframework.boot; +import java.io.File; +import java.io.IOException; +import java.net.JarURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.util.jar.Attributes; +import java.util.jar.JarFile; + /** * Class that exposes the Spring Boot version. Fetches the "Implementation-Version" * manifest attribute from the jar file. @@ -40,8 +48,35 @@ public final class SpringBootVersion { * @see Package#getImplementationVersion() */ public static String getVersion() { - Package pkg = SpringBootVersion.class.getPackage(); - return (pkg != null) ? pkg.getImplementationVersion() : null; + return determineSpringBootVersion(); + } + + private static String determineSpringBootVersion() { + String implementationVersion = SpringBootVersion.class.getPackage() + .getImplementationVersion(); + if (implementationVersion != null) { + return implementationVersion; + } + URL codeSourceLocation = SpringBootVersion.class.getProtectionDomain() + .getCodeSource().getLocation(); + try { + URLConnection connection = codeSourceLocation.openConnection(); + if (connection instanceof JarURLConnection) { + return getImplementationVersion( + ((JarURLConnection) connection).getJarFile()); + } + try (JarFile jarFile = new JarFile(new File(codeSourceLocation.toURI()))) { + return getImplementationVersion(jarFile); + } + } + catch (Exception ex) { + return null; + } + } + + private static String getImplementationVersion(JarFile jarFile) throws IOException { + return jarFile.getManifest().getMainAttributes() + .getValue(Attributes.Name.IMPLEMENTATION_VERSION); } }