diff --git a/spring-boot-cli/pom.xml b/spring-boot-cli/pom.xml index 7716e22a43f..e7ee726736e 100644 --- a/spring-boot-cli/pom.xml +++ b/spring-boot-cli/pom.xml @@ -220,7 +220,7 @@ copy-dependencies - ${project.build.directory}/assembly/lib + ${project.build.directory}/assembly/BOOT-INF/lib runtime diff --git a/spring-boot-cli/src/main/assembly/jar-with-dependencies.xml b/spring-boot-cli/src/main/assembly/jar-with-dependencies.xml index e58cf8cf218..b0687983c09 100644 --- a/spring-boot-cli/src/main/assembly/jar-with-dependencies.xml +++ b/spring-boot-cli/src/main/assembly/jar-with-dependencies.xml @@ -15,6 +15,7 @@ ${project.groupId}:${project.artifactId} true + BOOT-INF/classes/ diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/archive/PackagedSpringApplicationLauncher.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/archive/PackagedSpringApplicationLauncher.java index e05c6d12c9a..abc07ef8f22 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/archive/PackagedSpringApplicationLauncher.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/archive/PackagedSpringApplicationLauncher.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. @@ -52,7 +52,7 @@ public final class PackagedSpringApplicationLauncher { } private Object[] getSources(URLClassLoader classLoader) throws Exception { - Enumeration urls = classLoader.findResources("META-INF/MANIFEST.MF"); + Enumeration urls = classLoader.getResources("META-INF/MANIFEST.MF"); while (urls.hasMoreElements()) { URL url = urls.nextElement(); Manifest manifest = new Manifest(url.openStream()); diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MultiProjectRepackagingTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MultiProjectRepackagingTests.java index ac83d90e310..b8296184e34 100644 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MultiProjectRepackagingTests.java +++ b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MultiProjectRepackagingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 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. @@ -42,8 +42,9 @@ public class MultiProjectRepackagingTests { File buildLibs = new File( "target/multi-project-transitive-file-dependency/main/build/libs"); JarFile jarFile = new JarFile(new File(buildLibs, "main.jar")); - assertThat(jarFile.getEntry("lib/commons-logging-1.1.3.jar")).isNotNull(); - assertThat(jarFile.getEntry("lib/foo.jar")).isNotNull(); + assertThat(jarFile.getEntry("BOOT-INF/lib/commons-logging-1.1.3.jar")) + .isNotNull(); + assertThat(jarFile.getEntry("BOOT-INF/lib/foo.jar")).isNotNull(); jarFile.close(); } @@ -57,7 +58,7 @@ public class MultiProjectRepackagingTests { "target/multi-project-common-file-dependency/build/libs"); JarFile jarFile = new JarFile( new File(buildLibs, "multi-project-common-file-dependency.jar")); - assertThat(jarFile.getEntry("lib/foo.jar")).isNotNull(); + assertThat(jarFile.getEntry("BOOT-INF/lib/foo.jar")).isNotNull(); jarFile.close(); } @@ -70,7 +71,7 @@ public class MultiProjectRepackagingTests { File buildLibs = new File( "target/multi-project-runtime-project-dependency/projectA/build/libs"); JarFile jarFile = new JarFile(new File(buildLibs, "projectA.jar")); - assertThat(jarFile.getEntry("lib/projectB.jar")).isNotNull(); + assertThat(jarFile.getEntry("BOOT-INF/lib/projectB.jar")).isNotNull(); jarFile.close(); } diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/RepackagingTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/RepackagingTests.java index 87b62ccdaf2..d52cf179fcd 100644 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/RepackagingTests.java +++ b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/RepackagingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 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. @@ -144,7 +144,7 @@ public class RepackagingTests { .run(); File buildLibs = new File("target/repackage/build/libs"); JarFile jarFile = new JarFile(new File(buildLibs, "repackage.jar")); - assertThat(jarFile.getEntry("lib/foo.jar")).isNotNull(); + assertThat(jarFile.getEntry("BOOT-INF/lib/foo.jar")).isNotNull(); jarFile.close(); } @@ -166,7 +166,7 @@ public class RepackagingTests { private boolean isDevToolsJarIncluded(File repackageFile) throws IOException { JarFile jarFile = new JarFile(repackageFile); try { - String name = "lib/spring-boot-devtools-" + BOOT_VERSION + ".jar"; + String name = "BOOT-INF/lib/spring-boot-devtools-" + BOOT_VERSION + ".jar"; return jarFile.getEntry(name) != null; } finally { diff --git a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/JarWriter.java b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/JarWriter.java index 0643a4afc96..81c055a9039 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/JarWriter.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/JarWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 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. @@ -120,6 +120,11 @@ public class JarWriter { * @throws IOException if the entries cannot be written */ public void writeEntries(JarFile jarFile) throws IOException { + this.writeEntries(jarFile, new IdentityEntryTransformer()); + } + + void writeEntries(JarFile jarFile, EntryTransformer entryTransformer) + throws IOException { Enumeration entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); @@ -133,7 +138,7 @@ public class JarWriter { jarFile.getInputStream(entry)); } EntryWriter entryWriter = new InputStreamEntryWriter(inputStream, true); - writeEntry(entry, entryWriter); + writeEntry(entryTransformer.transform(entry), entryWriter); } finally { inputStream.close(); @@ -377,4 +382,25 @@ public class JarWriter { } } + /** + * An {@code EntryTransformer} enables the transformation of {@link JarEntry jar + * entries} during the writing process. + */ + interface EntryTransformer { + + JarEntry transform(JarEntry jarEntry); + } + + /** + * An {@code EntryTransformer} that returns the entry unchanged. + */ + private static final class IdentityEntryTransformer implements EntryTransformer { + + @Override + public JarEntry transform(JarEntry jarEntry) { + return jarEntry; + } + + } + } diff --git a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java index 8eb4bf091ba..3cebdc7a05c 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 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. @@ -60,7 +60,7 @@ public final class Layouts { /** * Executable JAR layout. */ - public static class Jar implements Layout { + public static class Jar implements RepackagingLayout { @Override public String getLauncherClassName() { @@ -69,7 +69,7 @@ public final class Layouts { @Override public String getLibraryDestination(String libraryName, LibraryScope scope) { - return "lib/"; + return "BOOT-INF/lib/"; } @Override @@ -77,6 +77,11 @@ public final class Layouts { return ""; } + @Override + public String getRepackagedClassesLocation() { + return "BOOT-INF/classes/"; + } + @Override public boolean isExecutable() { return true; diff --git a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java index bbe27db7e42..c9c59376ad4 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 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. @@ -24,9 +24,12 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.Manifest; +import org.springframework.boot.loader.tools.JarWriter.EntryTransformer; + /** * Utility class that can be used to repackage an archive so that it can be executed using * '{@literal java -jar}'. @@ -189,7 +192,14 @@ public class Repackager { writer.writeManifest(buildManifest(sourceJar)); Set seen = new HashSet(); writeNestedLibraries(unpackLibraries, seen, writer); - writer.writeEntries(sourceJar); + if (this.layout instanceof RepackagingLayout) { + writer.writeEntries(sourceJar, + new RenamingEntryTransformer(((RepackagingLayout) this.layout) + .getRepackagedClassesLocation())); + } + else { + writer.writeEntries(sourceJar); + } writeNestedLibraries(standardLibraries, seen, writer); if (this.layout.isExecutable()) { writer.writeLoaderClasses(); @@ -293,4 +303,47 @@ public class Repackager { } } + /** + * An {@code EntryTransformer} that renames entries by applying a prefix. + */ + private static final class RenamingEntryTransformer implements EntryTransformer { + + private final String namePrefix; + + private RenamingEntryTransformer(String namePrefix) { + this.namePrefix = namePrefix; + } + + @Override + public JarEntry transform(JarEntry entry) { + if (entry.getName().startsWith("META-INF/") + || entry.getName().startsWith("BOOT-INF/")) { + return entry; + } + JarEntry renamedEntry = new JarEntry(this.namePrefix + entry.getName()); + renamedEntry.setTime(entry.getTime()); + renamedEntry.setSize(entry.getSize()); + renamedEntry.setMethod(entry.getMethod()); + if (entry.getComment() != null) { + renamedEntry.setComment(entry.getComment()); + } + renamedEntry.setCompressedSize(entry.getCompressedSize()); + renamedEntry.setCrc(entry.getCrc()); + if (entry.getCreationTime() != null) { + renamedEntry.setCreationTime(entry.getCreationTime()); + } + if (entry.getExtra() != null) { + renamedEntry.setExtra(entry.getExtra()); + } + if (entry.getLastAccessTime() != null) { + renamedEntry.setLastAccessTime(entry.getLastAccessTime()); + } + if (entry.getLastModifiedTime() != null) { + renamedEntry.setLastModifiedTime(entry.getLastModifiedTime()); + } + return renamedEntry; + } + + } + } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JavaAgentDetector.java b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RepackagingLayout.java similarity index 58% rename from spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JavaAgentDetector.java rename to spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RepackagingLayout.java index 8fa5b9abb74..e14def52b0a 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JavaAgentDetector.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RepackagingLayout.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 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. @@ -14,24 +14,21 @@ * limitations under the License. */ -package org.springframework.boot.loader; - -import java.net.URL; +package org.springframework.boot.loader.tools; /** - * A strategy for detecting Java agents. + * A specialization of {@link Layout} that repackages an existing archive by moving its + * content to a new location. * * @author Andy Wilkinson - * @since 1.1.0 + * @since 1.4.0 */ -public interface JavaAgentDetector { +public interface RepackagingLayout extends Layout { /** - * Returns {@code true} if {@code url} points to a Java agent jar file, otherwise - * {@code false} is returned. - * @param url The url to examine - * @return if the URL points to a Java agent + * Returns the location to which classes should be moved. + * @return the repackaged classes location */ - boolean isJavaAgentJar(URL url); + String getRepackagedClassesLocation(); } diff --git a/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/LayoutsTests.java b/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/LayoutsTests.java index 42ee8fad23a..e7a32fed129 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/LayoutsTests.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/LayoutsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 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. @@ -64,13 +64,13 @@ public class LayoutsTests { public void jarLayout() throws Exception { Layout layout = new Layouts.Jar(); assertThat(layout.getLibraryDestination("lib.jar", LibraryScope.COMPILE)) - .isEqualTo("lib/"); + .isEqualTo("BOOT-INF/lib/"); assertThat(layout.getLibraryDestination("lib.jar", LibraryScope.CUSTOM)) - .isEqualTo("lib/"); + .isEqualTo("BOOT-INF/lib/"); assertThat(layout.getLibraryDestination("lib.jar", LibraryScope.PROVIDED)) - .isEqualTo("lib/"); + .isEqualTo("BOOT-INF/lib/"); assertThat(layout.getLibraryDestination("lib.jar", LibraryScope.RUNTIME)) - .isEqualTo("lib/"); + .isEqualTo("BOOT-INF/lib/"); } @Test diff --git a/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/RepackagerTests.java b/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/RepackagerTests.java index 8d0e2707f4d..83f92b98bc0 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/RepackagerTests.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/RepackagerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 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. @@ -291,7 +291,7 @@ public class RepackagerTests { final File libNonJarFile = this.temporaryFolder.newFile(); FileCopyUtils.copy(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, libNonJarFile); this.testJarFile.addClass("a/b/C.class", ClassWithMainMethod.class); - this.testJarFile.addFile("lib/" + libJarFileToUnpack.getName(), + this.testJarFile.addFile("BOOT-INF/lib/" + libJarFileToUnpack.getName(), libJarFileToUnpack); File file = this.testJarFile.getFile(); libJarFile.setLastModified(JAN_1_1980); @@ -305,12 +305,13 @@ public class RepackagerTests { callback.library(new Library(libNonJarFile, LibraryScope.COMPILE)); } }); - assertThat(hasEntry(file, "lib/" + libJarFile.getName())).isTrue(); - assertThat(hasEntry(file, "lib/" + libJarFileToUnpack.getName())).isTrue(); - assertThat(hasEntry(file, "lib/" + libNonJarFile.getName())).isFalse(); - JarEntry entry = getEntry(file, "lib/" + libJarFile.getName()); + assertThat(hasEntry(file, "BOOT-INF/lib/" + libJarFile.getName())).isTrue(); + assertThat(hasEntry(file, "BOOT-INF/lib/" + libJarFileToUnpack.getName())) + .isTrue(); + assertThat(hasEntry(file, "BOOT-INF/lib/" + libNonJarFile.getName())).isFalse(); + JarEntry entry = getEntry(file, "BOOT-INF/lib/" + libJarFile.getName()); assertThat(entry.getTime()).isEqualTo(JAN_1_1985); - entry = getEntry(file, "lib/" + libJarFileToUnpack.getName()); + entry = getEntry(file, "BOOT-INF/lib/" + libJarFileToUnpack.getName()); assertThat(entry.getComment()).startsWith("UNPACK:"); assertThat(entry.getComment().length()).isEqualTo(47); } @@ -395,9 +396,10 @@ public class RepackagerTests { }); JarFile jarFile = new JarFile(file); try { - assertThat(jarFile.getEntry("lib/" + nestedFile.getName()).getMethod()) - .isEqualTo(ZipEntry.STORED); - assertThat(jarFile.getEntry("test/nested.jar").getMethod()) + assertThat( + jarFile.getEntry("BOOT-INF/lib/" + nestedFile.getName()).getMethod()) + .isEqualTo(ZipEntry.STORED); + assertThat(jarFile.getEntry("BOOT-INF/classes/test/nested.jar").getMethod()) .isEqualTo(ZipEntry.STORED); } finally { @@ -432,7 +434,8 @@ public class RepackagerTests { TestJarFile nested = new TestJarFile(this.temporaryFolder); nested.addClass("a/b/C.class", ClassWithoutMainMethod.class); final File nestedFile = nested.getFile(); - this.testJarFile.addFile("lib/" + nestedFile.getName(), nested.getFile()); + this.testJarFile.addFile("BOOT-INF/lib/" + nestedFile.getName(), + nested.getFile()); this.testJarFile.addClass("A.class", ClassWithMainMethod.class); File file = this.testJarFile.getFile(); Repackager repackager = new Repackager(file); @@ -446,8 +449,9 @@ public class RepackagerTests { }); JarFile jarFile = new JarFile(file); try { - assertThat(jarFile.getEntry("lib/" + nestedFile.getName()).getComment()) - .startsWith("UNPACK:"); + assertThat( + jarFile.getEntry("BOOT-INF/lib/" + nestedFile.getName()).getComment()) + .startsWith("UNPACK:"); } finally { jarFile.close(); @@ -460,7 +464,8 @@ public class RepackagerTests { TestJarFile nested = new TestJarFile(this.temporaryFolder); nested.addClass("a/b/C.class", ClassWithoutMainMethod.class); final File nestedFile = nested.getFile(); - this.testJarFile.addFile("lib/" + nestedFile.getName(), nested.getFile()); + this.testJarFile.addFile("BOOT-INF/lib/" + nestedFile.getName(), + nested.getFile()); this.testJarFile.addClass("A.class", ClassWithMainMethod.class); File file = this.testJarFile.getFile(); Repackager repackager = new Repackager(file); @@ -478,7 +483,7 @@ public class RepackagerTests { }); JarFile jarFile = new JarFile(file); try { - assertThat(jarFile.getEntry("lib/" + nestedFile.getName()).getSize()) + assertThat(jarFile.getEntry("BOOT-INF/lib/" + nestedFile.getName()).getSize()) .isEqualTo(sourceLength); } finally { diff --git a/spring-boot-tools/spring-boot-loader/src/it/executable-props/pom.xml b/spring-boot-tools/spring-boot-loader/src/it/executable-props/pom.xml index 2bbfe1c7ecb..ac5eaa5184d 100644 --- a/spring-boot-tools/spring-boot-loader/src/it/executable-props/pom.xml +++ b/spring-boot-tools/spring-boot-loader/src/it/executable-props/pom.xml @@ -49,7 +49,7 @@ copy-dependencies - ${project.build.directory}/assembly/lib + ${project.build.directory}/assembly/BOOT-INF/lib diff --git a/spring-boot-tools/spring-boot-loader/src/it/executable-props/src/main/assembly/jar-with-dependencies.xml b/spring-boot-tools/spring-boot-loader/src/it/executable-props/src/main/assembly/jar-with-dependencies.xml index 44626f91aa1..1120acb7e2f 100644 --- a/spring-boot-tools/spring-boot-loader/src/it/executable-props/src/main/assembly/jar-with-dependencies.xml +++ b/spring-boot-tools/spring-boot-loader/src/it/executable-props/src/main/assembly/jar-with-dependencies.xml @@ -14,6 +14,7 @@ ${project.groupId}:${project.artifactId} + BOOT-INF/classes true diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/ExecutableArchiveLauncher.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/ExecutableArchiveLauncher.java index 6ecb93d3604..38edb926a6d 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/ExecutableArchiveLauncher.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/ExecutableArchiveLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 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. @@ -16,13 +16,8 @@ package org.springframework.boot.loader; -import java.net.URL; -import java.net.URLClassLoader; import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashSet; import java.util.List; -import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.Manifest; @@ -40,24 +35,16 @@ public abstract class ExecutableArchiveLauncher extends Launcher { private final Archive archive; - private final JavaAgentDetector javaAgentDetector; - public ExecutableArchiveLauncher() { - this(new InputArgumentsJavaAgentDetector()); - } - - public ExecutableArchiveLauncher(JavaAgentDetector javaAgentDetector) { try { this.archive = createArchive(); } catch (Exception ex) { throw new IllegalStateException(ex); } - this.javaAgentDetector = javaAgentDetector; } protected ExecutableArchiveLauncher(Archive archive) { - this.javaAgentDetector = new InputArgumentsJavaAgentDetector(); this.archive = archive; } @@ -92,31 +79,6 @@ public abstract class ExecutableArchiveLauncher extends Launcher { return archives; } - @Override - protected ClassLoader createClassLoader(URL[] urls) throws Exception { - Set copy = new LinkedHashSet(urls.length); - ClassLoader loader = getDefaultClassLoader(); - if (loader instanceof URLClassLoader) { - for (URL url : ((URLClassLoader) loader).getURLs()) { - if (addDefaultClassloaderUrl(urls, url)) { - copy.add(url); - } - } - } - Collections.addAll(copy, urls); - return super.createClassLoader(copy.toArray(new URL[copy.size()])); - } - - private boolean addDefaultClassloaderUrl(URL[] urls, URL url) { - String jarUrl = "jar:" + url + "!/"; - for (URL nestedUrl : urls) { - if (nestedUrl.equals(url) || nestedUrl.toString().equals(jarUrl)) { - return false; - } - } - return !this.javaAgentDetector.isJavaAgentJar(url); - } - /** * Determine if the specified {@link JarEntry} is a nested item that should be added * to the classpath. The method is called once for each entry. @@ -134,20 +96,4 @@ public abstract class ExecutableArchiveLauncher extends Launcher { protected void postProcessClassPathArchives(List archives) throws Exception { } - private static ClassLoader getDefaultClassLoader() { - ClassLoader classloader = null; - try { - classloader = Thread.currentThread().getContextClassLoader(); - } - catch (Throwable ex) { - // Cannot access thread context ClassLoader - falling back to system class - // loader... - } - if (classloader == null) { - // No thread context class loader -> use class loader of this class. - classloader = ExecutableArchiveLauncher.class.getClassLoader(); - } - return classloader; - } - } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/InputArgumentsJavaAgentDetector.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/InputArgumentsJavaAgentDetector.java deleted file mode 100644 index cc6fd47cf14..00000000000 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/InputArgumentsJavaAgentDetector.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2012-2014 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.loader; - -import java.io.File; -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.net.URL; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * A {@link JavaAgentDetector} that detects jars supplied via the {@code -javaagent} JVM - * input argument. - * - * @author Andy Wilkinson - * @since 1.1.0 - */ -public class InputArgumentsJavaAgentDetector implements JavaAgentDetector { - - private static final String JAVA_AGENT_PREFIX = "-javaagent:"; - - private final Set javaAgentJars; - - public InputArgumentsJavaAgentDetector() { - this(getInputArguments()); - } - - InputArgumentsJavaAgentDetector(List inputArguments) { - this.javaAgentJars = getJavaAgentJars(inputArguments); - } - - private static List getInputArguments() { - try { - return AccessController.doPrivileged(new PrivilegedAction>() { - @Override - public List run() { - return ManagementFactory.getRuntimeMXBean().getInputArguments(); - } - }); - } - catch (Exception ex) { - return Collections.emptyList(); - } - } - - private Set getJavaAgentJars(List inputArguments) { - Set javaAgentJars = new HashSet(); - for (String argument : inputArguments) { - String path = getJavaAgentJarPath(argument); - if (path != null) { - try { - javaAgentJars.add(new File(path).getCanonicalFile().toURI().toURL()); - } - catch (IOException ex) { - throw new IllegalStateException( - "Failed to determine canonical path of Java agent at path '" - + path + "'"); - } - } - } - return javaAgentJars; - } - - private String getJavaAgentJarPath(String arg) { - if (arg.startsWith(JAVA_AGENT_PREFIX)) { - String path = arg.substring(JAVA_AGENT_PREFIX.length()); - int equalsIndex = path.indexOf('='); - if (equalsIndex > -1) { - path = path.substring(0, equalsIndex); - } - return path; - } - return null; - } - - @Override - public boolean isJavaAgentJar(URL url) { - return this.javaAgentJars.contains(url); - } - -} diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JarLauncher.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JarLauncher.java index d004d0175f7..6f19c70c235 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JarLauncher.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/JarLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 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. @@ -22,13 +22,17 @@ import org.springframework.boot.loader.archive.Archive; /** * {@link Launcher} for JAR based archives. This launcher assumes that dependency jars are - * included inside a {@code /lib} directory. + * included inside a {@code /BOOT-INF/lib} and that application classes are included + * inside a {@code /BOOT-INF/classes} directory. * * @author Phillip Webb + * @author Andy Wilkinson */ public class JarLauncher extends ExecutableArchiveLauncher { - private static final String LIB = "lib/"; + static final String BOOT_INF_CLASSES = "BOOT-INF/classes/"; + + static final String BOOT_INF_LIB = "BOOT-INF/lib/"; public JarLauncher() { } @@ -39,7 +43,10 @@ public class JarLauncher extends ExecutableArchiveLauncher { @Override protected boolean isNestedArchive(Archive.Entry entry) { - return !entry.isDirectory() && entry.getName().startsWith(LIB); + if (entry.isDirectory()) { + return entry.getName().startsWith(BOOT_INF_CLASSES); + } + return entry.getName().startsWith(BOOT_INF_LIB); } @Override diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java index f9bfac9b2b2..1608792e7f8 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 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. @@ -23,13 +23,10 @@ import java.net.URLClassLoader; import java.net.URLConnection; import java.security.AccessController; import java.security.PrivilegedExceptionAction; -import java.util.Arrays; -import java.util.Collections; import java.util.Enumeration; import org.springframework.boot.loader.jar.Handler; import org.springframework.boot.loader.jar.JarFile; -import org.springframework.lang.UsesJava7; /** * {@link ClassLoader} used by the {@link Launcher}. @@ -40,10 +37,6 @@ import org.springframework.lang.UsesJava7; */ public class LaunchedURLClassLoader extends URLClassLoader { - private static LockProvider LOCK_PROVIDER = setupLockProvider(); - - private final ClassLoader rootClassLoader; - /** * Create a new {@link LaunchedURLClassLoader} instance. * @param urls the URLs from which to load classes and resources @@ -51,57 +44,21 @@ public class LaunchedURLClassLoader extends URLClassLoader { */ public LaunchedURLClassLoader(URL[] urls, ClassLoader parent) { super(urls, parent); - this.rootClassLoader = findRootClassLoader(parent); - } - - private ClassLoader findRootClassLoader(ClassLoader classLoader) { - while (classLoader != null) { - if (classLoader.getParent() == null) { - return classLoader; - } - classLoader = classLoader.getParent(); - } - return null; - } - - /** - * Gets the resource with the given {@code name}. Unlike a standard - * {@link ClassLoader}, this method will first search the root class loader. If the - * resource is not found, this method will call {@link #findResource(String)}. - */ - @Override - public URL getResource(String name) { - URL url = null; - if (this.rootClassLoader != null) { - url = this.rootClassLoader.getResource(name); - } - return (url == null ? findResource(name) : url); } @Override public URL findResource(String name) { + Handler.setUseFastConnectionExceptions(true); try { - if (name.equals("") && hasURLs()) { - return getURLs()[0]; - } - Handler.setUseFastConnectionExceptions(true); - try { - return super.findResource(name); - } - finally { - Handler.setUseFastConnectionExceptions(false); - } + return super.findResource(name); } - catch (IllegalArgumentException ex) { - return null; + finally { + Handler.setUseFastConnectionExceptions(false); } } @Override public Enumeration findResources(String name) throws IOException { - if (name.equals("") && hasURLs()) { - return Collections.enumeration(Arrays.asList(getURLs())); - } Handler.setUseFastConnectionExceptions(true); try { return super.findResources(name); @@ -111,106 +68,47 @@ public class LaunchedURLClassLoader extends URLClassLoader { } } - private boolean hasURLs() { - return getURLs().length > 0; - } - - /** - * Gets the resources with the given {@code name}. Returns a combination of the - * resources found by {@link #findResources(String)} and from - * {@link ClassLoader#getResources(String) getResources(String)} on the root class - * loader, if any. - */ - @Override - public Enumeration getResources(String name) throws IOException { - if (this.rootClassLoader == null) { - return findResources(name); - } - return new ResourceEnumeration(this.rootClassLoader.getResources(name), - findResources(name)); - } - - /** - * Attempt to load classes from the URLs before delegating to the parent loader. - */ @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - synchronized (LaunchedURLClassLoader.LOCK_PROVIDER.getLock(this, name)) { - Class loadedClass = findLoadedClass(name); - if (loadedClass == null) { - Handler.setUseFastConnectionExceptions(true); - try { - loadedClass = doLoadClass(name); - } - finally { - Handler.setUseFastConnectionExceptions(false); - } - } - if (resolve) { - resolveClass(loadedClass); - } - return loadedClass; - } - } - - private Class doLoadClass(String name) throws ClassNotFoundException { - - // 1) Try the root class loader + Handler.setUseFastConnectionExceptions(true); try { - if (this.rootClassLoader != null) { - return this.rootClassLoader.loadClass(name); - } + definePackageIfNecessary(name); + return super.loadClass(name, resolve); } - catch (Exception ex) { - // Ignore and continue - } - - // 2) Try to find locally - try { - findPackage(name); - Class cls = findClass(name); - return cls; - } - catch (Exception ex) { - // Ignore and continue - } - - // 3) Use standard loading - return super.loadClass(name, false); - } - - private void findPackage(final String name) throws ClassNotFoundException { - int lastDot = name.lastIndexOf('.'); - if (lastDot != -1) { - String packageName = name.substring(0, lastDot); - if (getPackage(packageName) == null) { - try { - definePackageForFindClass(name, packageName); - } - catch (Exception ex) { - // Swallow and continue - } - } + finally { + Handler.setUseFastConnectionExceptions(false); } } /** * Define a package before a {@code findClass} call is made. This is necessary to - * ensure that the appropriate manifest for nested JARs associated with the package. - * @param name the class name being found - * @param packageName the package + * ensure that the appropriate manifest for nested JARs is associated with the + * package. + * @param className the class name being found */ - private void definePackageForFindClass(final String name, final String packageName) { + private void definePackageIfNecessary(String className) { + int lastDot = className.lastIndexOf('.'); + if (lastDot >= 0) { + String packageName = className.substring(0, lastDot); + if (getPackage(packageName) == null) { + definePackage(packageName); + } + } + } + + private void definePackage(final String packageName) { try { AccessController.doPrivileged(new PrivilegedExceptionAction() { @Override public Object run() throws ClassNotFoundException { + String packageEntryName = packageName.replace(".", "/") + "/"; for (URL url : getURLs()) { try { if (url.getContent() instanceof JarFile) { JarFile jarFile = (JarFile) url.getContent(); - if (jarFile.getManifest() != null) { + if (jarFile.getEntry(packageEntryName) != null + && jarFile.getManifest() != null) { definePackage(packageName, jarFile.getManifest(), url); return null; @@ -242,6 +140,7 @@ public class LaunchedURLClassLoader extends URLClassLoader { } } catch (IOException ex) { + // Ignore } } @@ -254,76 +153,4 @@ public class LaunchedURLClassLoader extends URLClassLoader { } } - @UsesJava7 - private static LockProvider setupLockProvider() { - try { - ClassLoader.registerAsParallelCapable(); - return new Java7LockProvider(); - } - catch (NoSuchMethodError ex) { - return new LockProvider(); - } - } - - /** - * Strategy used to provide the synchronize lock object to use when loading classes. - */ - private static class LockProvider { - - public Object getLock(LaunchedURLClassLoader classLoader, String className) { - return classLoader; - } - - } - - /** - * Java 7 specific {@link LockProvider}. - */ - @UsesJava7 - private static class Java7LockProvider extends LockProvider { - - @Override - public Object getLock(LaunchedURLClassLoader classLoader, String className) { - return classLoader.getClassLoadingLock(className); - } - - } - - /** - * {@link Enumeration} implementation used for {@code getResources()}. - */ - private static class ResourceEnumeration implements Enumeration { - - private final Enumeration rootResources; - - private final Enumeration localResources; - - ResourceEnumeration(Enumeration rootResources, - Enumeration localResources) { - this.rootResources = rootResources; - this.localResources = localResources; - } - - @Override - public boolean hasMoreElements() { - try { - Handler.setUseFastConnectionExceptions(true); - return this.rootResources.hasMoreElements() - || this.localResources.hasMoreElements(); - } - finally { - Handler.setUseFastConnectionExceptions(false); - } - } - - @Override - public URL nextElement() { - if (this.rootResources.hasMoreElements()) { - return this.rootResources.nextElement(); - } - return this.localResources.nextElement(); - } - - } - } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/PropertiesLauncher.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/PropertiesLauncher.java index 59b810cfbe9..5607a4048d2 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/PropertiesLauncher.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/PropertiesLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 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. @@ -22,11 +22,8 @@ import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; -import java.net.URISyntaxException; import java.net.URL; -import java.net.URLClassLoader; import java.net.URLConnection; -import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -60,7 +57,7 @@ import org.springframework.boot.loader.util.SystemPropertyUtils; *
    *
  • {@code loader.path}: a comma-separated list of directories to append to the * classpath (containing file resources and/or nested archives in *.jar or *.zip). - * Defaults to {@code lib} in your application archive
  • + * Defaults to {@code BOOT-INF/classes,BOOT-INF/lib} in your application archive *
  • {@code loader.main}: the main method to delegate execution to once the class loader * is set up. No default, but will fall back to looking for a {@code Start-Class} in a * {@code MANIFEST.MF}, if there is one in ${loader.home}/META-INF.
  • @@ -123,12 +120,8 @@ public class PropertiesLauncher extends Launcher { private static final Pattern WORD_SEPARATOR = Pattern.compile("\\W+"); - private static final URL[] EMPTY_URLS = {}; - private final File home; - private final JavaAgentDetector javaAgentDetector; - private List paths = new ArrayList(); private final Properties properties = new Properties(); @@ -136,13 +129,8 @@ public class PropertiesLauncher extends Launcher { private Archive parent; public PropertiesLauncher() { - this(new InputArgumentsJavaAgentDetector()); - } - - PropertiesLauncher(JavaAgentDetector javaAgentDetector) { try { this.home = getHomeDirectory(); - this.javaAgentDetector = javaAgentDetector; initializeProperties(this.home); initializePaths(); this.parent = createArchive(); @@ -158,7 +146,7 @@ public class PropertiesLauncher extends Launcher { } private void initializeProperties(File home) throws Exception, IOException { - String config = "classpath:" + String config = "classpath:BOOT-INF/classes/" + SystemPropertyUtils.resolvePlaceholders( SystemPropertyUtils.getProperty(CONFIG_NAME, "application")) + ".properties"; @@ -425,7 +413,7 @@ public class PropertiesLauncher extends Launcher { lib.addAll(nested); } } - addParentClassLoaderEntries(lib); + addNestedEntries(lib); return lib; } @@ -482,82 +470,26 @@ public class PropertiesLauncher extends Launcher { return new FilteredArchive(this.parent, filter); } - private void addParentClassLoaderEntries(List lib) - throws IOException, URISyntaxException { - ClassLoader parentClassLoader = getClass().getClassLoader(); - List urls = new ArrayList(); - for (URL url : getURLs(parentClassLoader)) { - if (!this.javaAgentDetector.isJavaAgentJar(url)) { - Archive archive = createArchiveIfPossible(url); - if (archive != null) { - urls.add(archive); + private void addNestedEntries(List lib) { + // The parent archive might have "BOOT-INF/lib/" and "BOOT-INF/classes/" + // directories, meaning we are running from an executable JAR. We add nested + // entries from there with low priority (i.e. at end). + try { + lib.addAll(this.parent.getNestedArchives(new EntryFilter() { + + @Override + public boolean matches(Entry entry) { + if (entry.isDirectory()) { + return entry.getName().startsWith(JarLauncher.BOOT_INF_CLASSES); + } + return entry.getName().startsWith(JarLauncher.BOOT_INF_LIB); } - } - } - // The parent archive might have a "lib/" directory, meaning we are running from - // an executable JAR. We add nested entries from there with low priority (i.e. at - // end). - addNestedArchivesFromParent(urls); - for (Archive archive : urls) { - // But only add them if they are not already included - if (findArchive(lib, archive) < 0) { - lib.add(archive); - } - } - } - private Archive createArchiveIfPossible(URL url) - throws IOException, URISyntaxException { - if (url.toString().endsWith(".jar") || url.toString().endsWith(".zip")) { - return new JarFileArchive(new File(url.toURI())); + })); } - if (url.toString().endsWith("/*")) { - String name = url.getFile(); - File dir = new File(name.substring(0, name.length() - 1)); - return (dir.exists() ? new ExplodedArchive(dir, false) : null); + catch (IOException ex) { + // Ignore } - String filename = URLDecoder.decode(url.getFile(), "UTF-8"); - return new ExplodedArchive(new File(filename)); - } - - private void addNestedArchivesFromParent(List urls) { - int index = findArchive(urls, this.parent); - if (index >= 0) { - try { - Archive nested = getNestedArchive("lib/"); - if (nested != null) { - List extra = new ArrayList( - nested.getNestedArchives(new ArchiveEntryFilter())); - urls.addAll(index + 1, extra); - } - } - catch (Exception ex) { - // ignore - } - } - } - - private int findArchive(List urls, Archive archive) { - // Do not rely on Archive to have an equals() method. Look for the archive by - // matching strings. - if (archive == null) { - return -1; - } - int i = 0; - for (Archive url : urls) { - if (url.toString().equals(archive.toString())) { - return i; - } - i++; - } - return -1; - } - - private URL[] getURLs(ClassLoader classLoader) { - if (classLoader instanceof URLClassLoader) { - return ((URLClassLoader) classLoader).getURLs(); - } - return EMPTY_URLS; } private String cleanupPath(String path) { diff --git a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/ExecutableArchiveLauncherTests.java b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/ExecutableArchiveLauncherTests.java deleted file mode 100644 index cadfba4fe5d..00000000000 --- a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/ExecutableArchiveLauncherTests.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2012-2014 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.loader; - -import java.io.File; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.concurrent.Callable; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import org.springframework.boot.loader.archive.Archive.Entry; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.given; - -/** - * Tests for {@link ExecutableArchiveLauncher} - * - * @author Andy Wilkinson - */ -public class ExecutableArchiveLauncherTests { - - @Mock - private JavaAgentDetector javaAgentDetector; - - private ExecutableArchiveLauncher launcher; - - @Before - public void setupMocks() { - MockitoAnnotations.initMocks(this); - - this.launcher = new UnitTestExecutableArchiveLauncher(this.javaAgentDetector); - } - - @Test - public void createdClassLoaderContainsUrlsFromThreadContextClassLoader() - throws Exception { - final URL[] urls = new URL[] { new URL("file:one"), new URL("file:two") }; - - doWithTccl(new URLClassLoader(urls), new Callable() { - - @Override - public Void call() throws Exception { - ClassLoader classLoader = ExecutableArchiveLauncherTests.this.launcher - .createClassLoader(new URL[0]); - assertClassLoaderUrls(classLoader, urls); - return null; - } - }); - } - - @Test - public void javaAgentJarsAreExcludedFromClasspath() throws Exception { - URL javaAgent = new File("my-agent.jar").getCanonicalFile().toURI().toURL(); - final URL one = new URL("file:one"); - given(this.javaAgentDetector.isJavaAgentJar(javaAgent)).willReturn(true); - doWithTccl(new URLClassLoader(new URL[] { javaAgent, one }), - new Callable() { - - @Override - public Void call() throws Exception { - ClassLoader classLoader = ExecutableArchiveLauncherTests.this.launcher - .createClassLoader(new URL[0]); - assertClassLoaderUrls(classLoader, new URL[] { one }); - return null; - } - }); - } - - private void assertClassLoaderUrls(ClassLoader classLoader, URL[] urls) { - assertThat(classLoader).isInstanceOf(URLClassLoader.class); - assertThat(((URLClassLoader) classLoader).getURLs()).isEqualTo(urls); - } - - private void doWithTccl(ClassLoader classLoader, Callable action) - throws Exception { - ClassLoader old = Thread.currentThread().getContextClassLoader(); - try { - Thread.currentThread().setContextClassLoader(classLoader); - action.call(); - } - finally { - Thread.currentThread().setContextClassLoader(old); - } - } - - private static final class UnitTestExecutableArchiveLauncher - extends ExecutableArchiveLauncher { - - UnitTestExecutableArchiveLauncher(JavaAgentDetector javaAgentDetector) { - super(javaAgentDetector); - } - - @Override - protected boolean isNestedArchive(Entry entry) { - return false; - } - } - -} diff --git a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/InputArgumentsJavaAgentDetectorTests.java b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/InputArgumentsJavaAgentDetectorTests.java deleted file mode 100644 index 5ca75e65e0d..00000000000 --- a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/InputArgumentsJavaAgentDetectorTests.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2012-2014 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.loader; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.util.Arrays; - -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link InputArgumentsJavaAgentDetector} - * - * @author Andy Wilkinson - */ -public class InputArgumentsJavaAgentDetectorTests { - - @Test - public void nonAgentJarsDoNotProduceFalsePositives() - throws MalformedURLException, IOException { - InputArgumentsJavaAgentDetector detector = new InputArgumentsJavaAgentDetector( - Arrays.asList("-javaagent:my-agent.jar")); - assertThat(detector.isJavaAgentJar( - new File("something-else.jar").getCanonicalFile().toURI().toURL())) - .isFalse(); - } - - @Test - public void singleJavaAgent() throws MalformedURLException, IOException { - InputArgumentsJavaAgentDetector detector = new InputArgumentsJavaAgentDetector( - Arrays.asList("-javaagent:my-agent.jar")); - assertThat(detector.isJavaAgentJar( - new File("my-agent.jar").getCanonicalFile().toURI().toURL())).isTrue(); - } - - @Test - public void singleJavaAgentWithOptions() throws MalformedURLException, IOException { - InputArgumentsJavaAgentDetector detector = new InputArgumentsJavaAgentDetector( - Arrays.asList("-javaagent:my-agent.jar=a=alpha,b=bravo")); - assertThat(detector.isJavaAgentJar( - new File("my-agent.jar").getCanonicalFile().toURI().toURL())).isTrue(); - } - - @Test - public void multipleJavaAgents() throws MalformedURLException, IOException { - InputArgumentsJavaAgentDetector detector = new InputArgumentsJavaAgentDetector( - Arrays.asList("-javaagent:my-agent.jar", - "-javaagent:my-other-agent.jar")); - assertThat(detector.isJavaAgentJar( - new File("my-agent.jar").getCanonicalFile().toURI().toURL())).isTrue(); - assertThat(detector.isJavaAgentJar( - new File("my-other-agent.jar").getCanonicalFile().toURI().toURL())) - .isTrue(); - } - -} diff --git a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/LaunchedURLClassLoaderTests.java b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/LaunchedURLClassLoaderTests.java index bcb9b997d64..954f75ab0a4 100644 --- a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/LaunchedURLClassLoaderTests.java +++ b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/LaunchedURLClassLoaderTests.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. @@ -39,19 +39,6 @@ public class LaunchedURLClassLoaderTests { @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); - @Test - public void resolveResourceFromWindowsFilesystem() throws Exception { - // This path is invalid - it should return null even on Windows. - // A regular URLClassLoader will deal with it gracefully. - assertThat(getClass().getClassLoader() - .getResource("c:\\Users\\user\\bar.properties")).isNull(); - LaunchedURLClassLoader loader = new LaunchedURLClassLoader( - new URL[] { new URL("jar:file:src/test/resources/jars/app.jar!/") }, - getClass().getClassLoader()); - // So we should too... - assertThat(loader.getResource("c:\\Users\\user\\bar.properties")).isNull(); - } - @Test public void resolveResourceFromArchive() throws Exception { LaunchedURLClassLoader loader = new LaunchedURLClassLoader( diff --git a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/PropertiesLauncherTests.java b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/PropertiesLauncherTests.java index d0fb1c49895..c7da9d08348 100644 --- a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/PropertiesLauncherTests.java +++ b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/PropertiesLauncherTests.java @@ -22,21 +22,17 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; import java.util.Collections; -import java.util.List; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.boot.loader.archive.Archive; import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.verify; /** * Tests for {@link PropertiesLauncher}. @@ -46,9 +42,6 @@ import static org.mockito.Mockito.verify; */ public class PropertiesLauncherTests { - @Mock - private JavaAgentDetector javaAgentDetector; - @Rule public OutputCapture output = new OutputCapture(); @@ -195,21 +188,6 @@ public class PropertiesLauncherTests { .isEqualTo("[foo, bar]"); } - @Test - public void testJavaAgentJarsAreExcludedFromClasspath() throws Exception { - List allArchives = new PropertiesLauncher().getClassPathArchives(); - URL[] parentUrls = ((URLClassLoader) getClass().getClassLoader()).getURLs(); - for (URL url : parentUrls) { - given(this.javaAgentDetector.isJavaAgentJar(url)).willReturn(true); - } - List nonAgentArchives = new PropertiesLauncher(this.javaAgentDetector) - .getClassPathArchives(); - assertThat(nonAgentArchives).hasSize(allArchives.size() - parentUrls.length); - for (URL url : parentUrls) { - verify(this.javaAgentDetector).isJavaAgentJar(url); - } - } - private void waitFor(String value) throws Exception { int count = 0; boolean timeout = false; diff --git a/spring-boot-tools/spring-boot-loader/src/test/resources/application.properties b/spring-boot-tools/spring-boot-loader/src/test/resources/BOOT-INF/classes/application.properties similarity index 100% rename from spring-boot-tools/spring-boot-loader/src/test/resources/application.properties rename to spring-boot-tools/spring-boot-loader/src/test/resources/BOOT-INF/classes/application.properties diff --git a/spring-boot-tools/spring-boot-loader/src/test/resources/foo.properties b/spring-boot-tools/spring-boot-loader/src/test/resources/BOOT-INF/classes/foo.properties similarity index 100% rename from spring-boot-tools/spring-boot-loader/src/test/resources/foo.properties rename to spring-boot-tools/spring-boot-loader/src/test/resources/BOOT-INF/classes/foo.properties diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-lib-name-conflict/verify.groovy b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-lib-name-conflict/verify.groovy index 18782c40193..aa5cb898e9e 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-lib-name-conflict/verify.groovy +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-lib-name-conflict/verify.groovy @@ -1,3 +1,19 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import java.io.*; import org.springframework.boot.maven.*; @@ -6,8 +22,8 @@ new Verify.JarArchiveVerification(f, Verify.SAMPLE_APP) { @Override protected void verifyZipEntries(Verify.ArchiveVerifier verifier) throws Exception { super.verifyZipEntries(verifier) - verifier.assertHasEntryNameStartingWith("lib/org.springframework.boot.maven.it-acme-lib-0.0.1.BUILD-SNAPSHOT.jar") - verifier.assertHasEntryNameStartingWith("lib/org.springframework.boot.maven.it.another-acme-lib-0.0.1.BUILD-SNAPSHOT.jar") + verifier.assertHasEntryNameStartingWith("BOOT-INF/lib/org.springframework.boot.maven.it-acme-lib-0.0.1.BUILD-SNAPSHOT.jar") + verifier.assertHasEntryNameStartingWith("BOOT-INF/lib/org.springframework.boot.maven.it.another-acme-lib-0.0.1.BUILD-SNAPSHOT.jar") } }.verify(); diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-with-unpack/verify.groovy b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-with-unpack/verify.groovy index f16e86e7410..ee238895662 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-with-unpack/verify.groovy +++ b/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-with-unpack/verify.groovy @@ -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. @@ -22,7 +22,7 @@ new Verify.JarArchiveVerification(f, Verify.SAMPLE_APP) { @Override protected void verifyZipEntries(Verify.ArchiveVerifier verifier) throws Exception { super.verifyZipEntries(verifier) - verifier.assertHasUnpackEntry("lib/spring-core-") - verifier.assertHasNonUnpackEntry("lib/spring-context-") + verifier.assertHasUnpackEntry("BOOT-INF/lib/spring-core-") + verifier.assertHasNonUnpackEntry("BOOT-INF/lib/spring-context-") } }.verify(); diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java b/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java index 351d20ae4ee..390c1085eb4 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 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. @@ -218,14 +218,15 @@ public final class Verify { @Override protected void verifyZipEntries(ArchiveVerifier verifier) throws Exception { super.verifyZipEntries(verifier); - verifier.assertHasEntryNameStartingWith("lib/spring-context"); - verifier.assertHasEntryNameStartingWith("lib/spring-core"); - verifier.assertHasEntryNameStartingWith("lib/javax.servlet-api-3"); + verifier.assertHasEntryNameStartingWith("BOOT-INF/lib/spring-context"); + verifier.assertHasEntryNameStartingWith("BOOT-INF/lib/spring-core"); + verifier.assertHasEntryNameStartingWith("BOOT-INF/lib/javax.servlet-api-3"); assertThat(verifier - .hasEntry("org/" + "springframework/boot/loader/JarLauncher.class")) + .hasEntry("org/springframework/boot/loader/JarLauncher.class")) .as("Unpacked launcher classes").isTrue(); - assertThat(verifier.hasEntry("org/" + "test/SampleApplication.class")) - .as("Own classes").isTrue(); + assertThat(verifier + .hasEntry("BOOT-INF/classes/org/test/SampleApplication.class")) + .as("Own classes").isTrue(); } @Override