From ec8fb614f707e5f3bf8f7690e8384e1552a24570 Mon Sep 17 00:00:00 2001 From: Hendrig Sellik Date: Sat, 9 Mar 2019 12:00:59 +0100 Subject: [PATCH 1/2] 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 2e6ea56a65..9eea37bd88 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); } } From 15f28dcc68be23e15bece7b285051a23cc4c0290 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 18 Apr 2019 15:08:10 +0100 Subject: [PATCH 2/2] Polish "Determine Spring Boot version correctly when using module path" See gh-16182 --- .../boot/SpringBootVersion.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 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 9eea37bd88..1412fd3de5 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -22,18 +22,23 @@ import java.net.JarURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.jar.Attributes; +import java.util.jar.Attributes.Name; import java.util.jar.JarFile; /** - * Class that exposes the Spring Boot version. Fetches the "Implementation-Version" - * manifest attribute from the jar file. + * Class that exposes the Spring Boot version. Fetches the + * {@link Name#IMPLEMENTATION_VERSION Implementation-Version} manifest attribute from the + * jar file via {@link Package#getImplementationVersion()}, falling back to locating the + * jar file that contains this class and reading the {@code Implementation-Version} + * attribute from its manifest. *

- * Note that some ClassLoaders do not expose the package metadata, hence this class might - * not be able to determine the Spring Boot version in all environments. Consider using a - * reflection-based check instead: For example, checking for the presence of a specific - * Spring Boot method that you intend to call. + * This class might not be able to determine the Spring Boot version in all environments. + * Consider using a reflection-based check instead: For example, checking for the presence + * of a specific Spring Boot method that you intend to call. * * @author Drummond Dawson + * @author Hendrig Sellik + * @author Andy Wilkinson * @since 1.3.0 */ public final class SpringBootVersion {