From efc9dcc22b472f6f87659c5c60fc7a2c0e83b205 Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Sun, 18 Mar 2018 15:34:22 +0100 Subject: [PATCH] Fix ModifiedClassPathRunner tests if run via IDEA IntelliJ can shorten the classpath to a single classpath.jar in order to circumvent errors originating from a too long classpath. This breaks the filtering inside ModifiedClassPathRunner as the classpath contains only a single jar to match against. This can be fixed by applying a similar mechanism already provided for Surefire manifest-only booter JARs, which extracts the real classpath from the JAR's Manifest file. See gh-12535 --- .../classpath/ModifiedClassPathRunner.java | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/junit/runner/classpath/ModifiedClassPathRunner.java b/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/junit/runner/classpath/ModifiedClassPathRunner.java index 1c84589d5f4..7dc2af97cde 100644 --- a/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/junit/runner/classpath/ModifiedClassPathRunner.java +++ b/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/junit/runner/classpath/ModifiedClassPathRunner.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.List; import java.util.jar.Attributes; import java.util.jar.JarFile; +import java.util.regex.Pattern; import org.apache.maven.repository.internal.MavenRepositorySystemUtils; import org.eclipse.aether.DefaultRepositorySystemSession; @@ -64,6 +65,9 @@ import org.springframework.util.StringUtils; */ public class ModifiedClassPathRunner extends BlockJUnit4ClassRunner { + private static final Pattern INTELLIJ_CLASSPATH_JAR_PATTERN = Pattern.compile( + ".*classpath(\\d+)?.jar"); + public ModifiedClassPathRunner(Class testClass) throws InitializationError { super(testClass); } @@ -102,7 +106,7 @@ public class ModifiedClassPathRunner extends BlockJUnit4ClassRunner { private URL[] extractUrls(URLClassLoader classLoader) throws Exception { List extractedUrls = new ArrayList(); for (URL url : classLoader.getURLs()) { - if (isSurefireBooterJar(url)) { + if (isManifestOnlyJar(url)) { extractedUrls.addAll(extractUrlsFromManifestClassPath(url)); } else { @@ -112,10 +116,30 @@ public class ModifiedClassPathRunner extends BlockJUnit4ClassRunner { return extractedUrls.toArray(new URL[extractedUrls.size()]); } + private boolean isManifestOnlyJar(URL url) { + return isSurefireBooterJar(url) || isShortenedIntelliJJar(url); + } + private boolean isSurefireBooterJar(URL url) { return url.getPath().contains("surefirebooter"); } + private boolean isShortenedIntelliJJar(URL url) { + String urlPath = url.getPath(); + boolean isCandidate = INTELLIJ_CLASSPATH_JAR_PATTERN.matcher(urlPath).matches(); + if (isCandidate) { + try { + Attributes attributes = getManifestMainAttributesFromUrl(url); + String createdBy = attributes.getValue("Created-By"); + return createdBy != null && createdBy.contains("IntelliJ"); + } + catch (Exception ex) { + return false; + } + } + return false; + } + private List extractUrlsFromManifestClassPath(URL booterJar) throws Exception { List urls = new ArrayList(); for (String entry : getClassPath(booterJar)) { @@ -125,10 +149,15 @@ public class ModifiedClassPathRunner extends BlockJUnit4ClassRunner { } private String[] getClassPath(URL booterJar) throws Exception { - JarFile jarFile = new JarFile(new File(booterJar.toURI())); + Attributes attributes = getManifestMainAttributesFromUrl(booterJar); + return StringUtils.delimitedListToStringArray(attributes + .getValue(Attributes.Name.CLASS_PATH), " "); + } + + private Attributes getManifestMainAttributesFromUrl(URL url) throws Exception { + JarFile jarFile = new JarFile(new File(url.toURI())); try { - return StringUtils.delimitedListToStringArray(jarFile.getManifest() - .getMainAttributes().getValue(Attributes.Name.CLASS_PATH), " "); + return jarFile.getManifest().getMainAttributes(); } finally { jarFile.close();