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..1412fd3de5a 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. @@ -16,16 +16,29 @@ 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.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 { @@ -40,8 +53,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); } }