From c66da65e237e7561f64fcff75cce00e655c9906f Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 9 Jun 2016 20:41:30 -0700 Subject: [PATCH] Refine ApplicationHome detection logic Update the detection logic used in ApplicationHome to: - Deal with `!/` elements in URLs so that `BOOT-INF/classes` packaging works as expected. - Use the `start-class` when no explicit source class is provided to prevent accidentally picking a home next to a `spring-boot.jar` that happens to be on the classpath. - Ignore search logic when running from a unit test. Fixes gh-6129 --- .gitignore | 1 + .../springframework/boot/ApplicationHome.java | 73 +++++++++++++++++-- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 8c194c9549..79bc3142e8 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,4 @@ overridedb.* .DS_Store .factorypath dump.rdb +transaction-logs diff --git a/spring-boot/src/main/java/org/springframework/boot/ApplicationHome.java b/spring-boot/src/main/java/org/springframework/boot/ApplicationHome.java index 7c54dbb2a7..81ea61bcac 100644 --- a/spring-boot/src/main/java/org/springframework/boot/ApplicationHome.java +++ b/spring-boot/src/main/java/org/springframework/boot/ApplicationHome.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2016 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. @@ -18,12 +18,17 @@ package org.springframework.boot; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.net.JarURLConnection; import java.net.URL; import java.net.URLConnection; import java.security.CodeSource; import java.security.ProtectionDomain; +import java.util.Enumeration; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** @@ -51,17 +56,51 @@ public class ApplicationHome { * @param sourceClass the source class or {@code null} */ public ApplicationHome(Class sourceClass) { - this.source = findSource(sourceClass == null ? getClass() : sourceClass); + this.source = findSource(sourceClass == null ? getStartClass() : sourceClass); this.dir = findHomeDir(this.source); } + private Class getStartClass() { + try { + ClassLoader classLoader = getClass().getClassLoader(); + return getStartClass(classLoader.getResources("META-INF/MANIFEST.MF")); + } + catch (Exception ex) { + return null; + } + } + + private Class getStartClass(Enumeration manifestResources) { + while (manifestResources.hasMoreElements()) { + try { + InputStream inputStream = manifestResources.nextElement().openStream(); + try { + Manifest manifest = new Manifest(inputStream); + String startClass = manifest.getMainAttributes() + .getValue("Start-Class"); + if (startClass != null) { + return ClassUtils.forName(startClass, + getClass().getClassLoader()); + } + } + finally { + inputStream.close(); + } + } + catch (Exception ex) { + } + } + return null; + } + private File findSource(Class sourceClass) { try { - ProtectionDomain protectionDomain = sourceClass.getProtectionDomain(); - CodeSource codeSource = protectionDomain.getCodeSource(); + ProtectionDomain domain = (sourceClass == null ? null + : sourceClass.getProtectionDomain()); + CodeSource codeSource = (domain == null ? null : domain.getCodeSource()); URL location = (codeSource == null ? null : codeSource.getLocation()); File source = (location == null ? null : findSource(location)); - if (source != null && source.exists()) { + if (source != null && source.exists() && !isUnitTest()) { return source.getAbsoluteFile(); } return null; @@ -71,14 +110,36 @@ public class ApplicationHome { } } + private boolean isUnitTest() { + try { + for (StackTraceElement element : Thread.currentThread().getStackTrace()) { + if (element.getClassName().startsWith("org.junit.")) { + return true; + } + } + } + catch (Exception ex) { + } + return false; + } + private File findSource(URL location) throws IOException { URLConnection connection = location.openConnection(); if (connection instanceof JarURLConnection) { - return new File(((JarURLConnection) connection).getJarFile().getName()); + return getRootJarFile(((JarURLConnection) connection).getJarFile()); } return new File(location.getPath()); } + private File getRootJarFile(JarFile jarFile) { + String name = jarFile.getName(); + int separator = name.indexOf("!/"); + if (separator > 0) { + name = name.substring(0, separator); + } + return new File(name); + } + private File findHomeDir(File source) { File homeDir = source; homeDir = (homeDir == null ? findDefaultHomeDir() : homeDir);