diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/Context.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/Context.java index e5e05c393e..ae401d4695 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/Context.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/Context.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -36,7 +36,7 @@ import org.springframework.util.Assert; */ class Context { - private final File jarFile; + private final File archiveFile; private final File workingDir; @@ -46,23 +46,31 @@ class Context { * Create a new {@link Context} instance. */ Context() { - this(getSourceJarFile(), Paths.get(".").toAbsolutePath().normalize().toFile()); + this(getSourceArchiveFile(), Paths.get(".").toAbsolutePath().normalize().toFile()); } /** * Create a new {@link Context} instance with the specified value. - * @param jarFile the source jar file + * @param archiveFile the source archive file * @param workingDir the working directory */ - Context(File jarFile, File workingDir) { - Assert.state(jarFile != null && jarFile.isFile() && jarFile.exists() - && jarFile.getName().toLowerCase().endsWith(".jar"), "Unable to find source JAR"); - this.jarFile = jarFile; + Context(File archiveFile, File workingDir) { + Assert.state(isExistingFile(archiveFile) && isJarOrWar(archiveFile), "Unable to find source archive"); + this.archiveFile = archiveFile; this.workingDir = workingDir; - this.relativeDir = deduceRelativeDir(jarFile.getParentFile(), this.workingDir); + this.relativeDir = deduceRelativeDir(archiveFile.getParentFile(), this.workingDir); } - private static File getSourceJarFile() { + private boolean isExistingFile(File archiveFile) { + return archiveFile != null && archiveFile.isFile() && archiveFile.exists(); + } + + private boolean isJarOrWar(File jarFile) { + String name = jarFile.getName().toLowerCase(); + return name.endsWith(".jar") || name.endsWith(".war"); + } + + private static File getSourceArchiveFile() { try { ProtectionDomain domain = Context.class.getProtectionDomain(); CodeSource codeSource = (domain != null) ? domain.getCodeSource() : null; @@ -106,11 +114,11 @@ class Context { } /** - * Return the source jar file that is running in tools mode. - * @return the jar file + * Return the source archive file that is running in tools mode. + * @return the archive file */ - File getJarFile() { - return this.jarFile; + File getArchiveFile() { + return this.archiveFile; } /** @@ -122,11 +130,11 @@ class Context { } /** - * Return the directory relative to {@link #getWorkingDir()} that contains the jar or + * Return the directory relative to {@link #getWorkingDir()} that contains the archive or * {@code null} if none relative directory can be deduced. * @return the relative dir ending in {@code /} or {@code null} */ - String getRelativeJarDir() { + String getRelativeArchiveDir() { return this.relativeDir; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/ExtractCommand.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/ExtractCommand.java index cf159cc29e..f3a4921128 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/ExtractCommand.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/ExtractCommand.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -65,9 +65,9 @@ class ExtractCommand extends Command { mkDirs(new File(destination, layer)); } } - try (ZipInputStream zip = new ZipInputStream(new FileInputStream(this.context.getJarFile()))) { + try (ZipInputStream zip = new ZipInputStream(new FileInputStream(this.context.getArchiveFile()))) { ZipEntry entry = zip.getNextEntry(); - Assert.state(entry != null, "File '" + this.context.getJarFile().toString() + Assert.state(entry != null, "File '" + this.context.getArchiveFile().toString() + "' is not compatible with layertools; ensure jar file is valid and launch script is not enabled"); while (entry != null) { if (!entry.isDirectory()) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/HelpCommand.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/HelpCommand.java index 20444bd9db..70f5d385c3 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/HelpCommand.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/HelpCommand.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -99,7 +99,7 @@ class HelpCommand extends Command { } private String getJavaCommand() { - return "java -Djarmode=layertools -jar " + this.context.getJarFile().getName(); + return "java -Djarmode=layertools -jar " + this.context.getArchiveFile().getName(); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/IndexedLayers.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/IndexedLayers.java index 1ae27236b4..61826969c1 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/IndexedLayers.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/main/java/org/springframework/boot/jarmode/layertools/IndexedLayers.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -27,6 +27,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.jar.JarFile; +import java.util.jar.Manifest; import java.util.zip.ZipEntry; import org.springframework.util.Assert; @@ -34,7 +35,7 @@ import org.springframework.util.StreamUtils; import org.springframework.util.StringUtils; /** - * {@link Layers} implementation backed by a {@code BOOT-INF/layers.idx} file. + * {@link Layers} implementation backed by a {@code layers.idx} file. * * @author Phillip Webb * @author Madhura Bhave @@ -91,8 +92,10 @@ class IndexedLayers implements Layers { */ static IndexedLayers get(Context context) { try { - try (JarFile jarFile = new JarFile(context.getJarFile())) { - ZipEntry entry = jarFile.getEntry("BOOT-INF/layers.idx"); + try (JarFile jarFile = new JarFile(context.getArchiveFile())) { + Manifest manifest = jarFile.getManifest(); + String location = manifest.getMainAttributes().getValue("Spring-Boot-Layers-Index"); + ZipEntry entry = (location != null) ? jarFile.getEntry(location) : null; if (entry != null) { String indexFile = StreamUtils.copyToString(jarFile.getInputStream(entry), StandardCharsets.UTF_8); return new IndexedLayers(indexFile); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ContextTests.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ContextTests.java index 40057128c5..9fccdfd392 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ContextTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -50,20 +50,12 @@ class ContextTests { .withMessage("Unable to find source JAR"); } - @Test - void createWhenSourceIsNotJarThrowsException() throws Exception { - File zip = new File(this.temp, "test.zip"); - Files.createFile(zip.toPath()); - assertThatIllegalStateException().isThrownBy(() -> new Context(zip, this.temp)) - .withMessage("Unable to find source JAR"); - } - @Test void getJarFileReturnsJar() throws Exception { File jar = new File(this.temp, "test.jar"); Files.createFile(jar.toPath()); Context context = new Context(jar, this.temp); - assertThat(context.getJarFile()).isEqualTo(jar); + assertThat(context.getArchiveFile()).isEqualTo(jar); } @Test @@ -82,7 +74,7 @@ class ContextTests { File jar = new File(target, "test.jar"); Files.createFile(jar.toPath()); Context context = new Context(jar, this.temp); - assertThat(context.getRelativeJarDir()).isEqualTo("target"); + assertThat(context.getRelativeArchiveDir()).isEqualTo("target"); } @Test @@ -90,7 +82,7 @@ class ContextTests { File jar = new File(this.temp, "test.jar"); Files.createFile(jar.toPath()); Context context = new Context(jar, this.temp); - assertThat(context.getRelativeJarDir()).isNull(); + assertThat(context.getRelativeArchiveDir()).isNull(); } @Test @@ -102,7 +94,7 @@ class ContextTests { File jar = new File(directory1, "test.jar"); Files.createFile(jar.toPath()); Context context = new Context(jar, directory2); - assertThat(context.getRelativeJarDir()).isNull(); + assertThat(context.getRelativeArchiveDir()).isNull(); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ExtractCommandTests.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ExtractCommandTests.java index 21f2f7467f..62369825b5 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ExtractCommandTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ExtractCommandTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -69,7 +69,7 @@ class ExtractCommandTests { @Test void runExtractsLayers() throws Exception { - given(this.context.getJarFile()).willReturn(this.jarFile); + given(this.context.getArchiveFile()).willReturn(this.jarFile); given(this.context.getWorkingDir()).willReturn(this.extract); this.command.run(Collections.emptyMap(), Collections.emptyList()); assertThat(this.extract.list()).containsOnly("a", "b", "c", "d"); @@ -81,7 +81,7 @@ class ExtractCommandTests { @Test void runWhenHasDestinationOptionExtractsLayers() { - given(this.context.getJarFile()).willReturn(this.jarFile); + given(this.context.getArchiveFile()).willReturn(this.jarFile); File out = new File(this.extract, "out"); this.command.run(Collections.singletonMap(ExtractCommand.DESTINATION_OPTION, out.getAbsolutePath()), Collections.emptyList()); @@ -93,7 +93,7 @@ class ExtractCommandTests { @Test void runWhenHasLayerParamsExtractsLimitedLayers() { - given(this.context.getJarFile()).willReturn(this.jarFile); + given(this.context.getArchiveFile()).willReturn(this.jarFile); given(this.context.getWorkingDir()).willReturn(this.extract); this.command.run(Collections.emptyMap(), Arrays.asList("a", "c")); assertThat(this.extract.list()).containsOnly("a", "c"); @@ -107,7 +107,7 @@ class ExtractCommandTests { try (FileWriter writer = new FileWriter(file)) { writer.write("text"); } - given(this.context.getJarFile()).willReturn(file); + given(this.context.getArchiveFile()).willReturn(file); given(this.context.getWorkingDir()).willReturn(this.extract); assertThatIllegalStateException() .isThrownBy(() -> this.command.run(Collections.emptyMap(), Collections.emptyList())) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/HelpCommandTests.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/HelpCommandTests.java index 8f863cdfde..cf3994d25f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/HelpCommandTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/HelpCommandTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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 @@ class HelpCommandTests { @BeforeEach void setup() throws Exception { Context context = mock(Context.class); - given(context.getJarFile()).willReturn(createJarFile("test.jar")); + given(context.getArchiveFile()).willReturn(createJarFile("test.jar")); this.command = new HelpCommand(context, LayerToolsJarMode.Runner.getCommands(context)); this.out = new TestPrintStream(this); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/IndexedLayersTests.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/IndexedLayersTests.java index aedbc28437..6d39105a6a 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/IndexedLayersTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/IndexedLayersTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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,10 +16,14 @@ package org.springframework.boot.jarmode.layertools; +import java.io.File; +import java.io.FileOutputStream; import java.io.InputStreamReader; import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.springframework.core.io.ClassPathResource; import org.springframework.util.FileCopyUtils; @@ -37,6 +41,9 @@ import static org.mockito.Mockito.mock; */ class IndexedLayersTests { + @TempDir + File temp; + @Test void createWhenIndexFileIsEmptyThrowsException() { assertThatIllegalStateException().isThrownBy(() -> new IndexedLayers(" \n ")) @@ -82,8 +89,20 @@ class IndexedLayersTests { assertThat(layers.getLayer(mockEntry("a b/c d"))).isEqualTo("application"); } + @Test + void getShouldReturnIndexedLayersFromContext() throws Exception { + Context context = mock(Context.class); + given(context.getArchiveFile()).willReturn(createWarFile("test.war")); + IndexedLayers layers = IndexedLayers.get(context); + assertThat(layers.getLayer(mockEntry("WEB-INF/lib/a.jar"))).isEqualTo("test"); + } + private String getIndex() throws Exception { - ClassPathResource resource = new ClassPathResource("test-layers.idx", getClass()); + return getIndex("test-layers.idx"); + } + + private String getIndex(String fileName) throws Exception { + ClassPathResource resource = new ClassPathResource(fileName, getClass()); InputStreamReader reader = new InputStreamReader(resource.getInputStream()); return FileCopyUtils.copyToString(reader); } @@ -94,4 +113,23 @@ class IndexedLayersTests { return entry; } + private File createWarFile(String name) throws Exception { + File file = new File(this.temp, name); + try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(file))) { + out.putNextEntry(new ZipEntry("WEB-INF/lib/a/")); + out.closeEntry(); + out.putNextEntry(new ZipEntry("WEB-INF/lib/a/a.jar")); + out.closeEntry(); + out.putNextEntry(new ZipEntry("WEB-INF/classes/Demo.class")); + out.closeEntry(); + out.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF")); + out.write(getIndex("test-manifest.MF").getBytes()); + out.closeEntry(); + out.putNextEntry(new ZipEntry("WEB-INF/layers.idx")); + out.write(getIndex("test-war-layers.idx").getBytes()); + out.closeEntry(); + } + return file; + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/LayerToolsJarModeTests.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/LayerToolsJarModeTests.java index 6e4c95fe5a..a3db809b25 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/LayerToolsJarModeTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/LayerToolsJarModeTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -55,7 +55,7 @@ class LayerToolsJarModeTests { @BeforeEach void setup() throws Exception { Context context = mock(Context.class); - given(context.getJarFile()).willReturn(createJarFile("test.jar")); + given(context.getArchiveFile()).willReturn(createJarFile("test.jar")); this.out = new TestPrintStream(this); this.systemOut = System.out; System.setOut(this.out); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ListCommandTests.java b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ListCommandTests.java index 0c88c68e66..a0dbaf76cd 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ListCommandTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/java/org/springframework/boot/jarmode/layertools/ListCommandTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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 @@ class ListCommandTests { @BeforeEach void setup() throws Exception { this.jarFile = createJarFile("test.jar"); - given(this.context.getJarFile()).willReturn(this.jarFile); + given(this.context.getArchiveFile()).willReturn(this.jarFile); this.command = new ListCommand(this.context); this.out = new TestPrintStream(this); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/resources/org/springframework/boot/jarmode/layertools/test-manifest.MF b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/resources/org/springframework/boot/jarmode/layertools/test-manifest.MF new file mode 100644 index 0000000000..8da12d2369 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/resources/org/springframework/boot/jarmode/layertools/test-manifest.MF @@ -0,0 +1,12 @@ +Manifest-Version: 1.0 +Created-By: Maven WAR Plugin 3.3.1 +Build-Jdk-Spec: 11 +Implementation-Title: demo +Implementation-Version: 0.0.1-SNAPSHOT +Main-Class: org.springframework.boot.loader.WarLauncher +Start-Class: com.example.DemoApplication +Spring-Boot-Version: 2.5.0-SNAPSHOT +Spring-Boot-Classes: WEB-INF/classes/ +Spring-Boot-Lib: WEB-INF/lib/ +Spring-Boot-Classpath-Index: WEB-INF/classpath.idx +Spring-Boot-Layers-Index: WEB-INF/layers.idx diff --git a/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/resources/org/springframework/boot/jarmode/layertools/test-war-layers.idx b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/resources/org/springframework/boot/jarmode/layertools/test-war-layers.idx new file mode 100644 index 0000000000..0f0d3df5ba --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-jarmode-layertools/src/test/resources/org/springframework/boot/jarmode/layertools/test-war-layers.idx @@ -0,0 +1,6 @@ +- "test": + - "WEB-INF/lib/a.jar" + - "WEB-INF/lib/b.jar" +- "empty": +- "application": + - "WEB-INF/classes/Demo.class" diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/AbstractJarWriter.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/AbstractJarWriter.java index 67b1ad5eb3..b3e2da1b5b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/AbstractJarWriter.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/AbstractJarWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -30,6 +30,7 @@ import java.util.Collection; import java.util.Enumeration; import java.util.HashSet; import java.util.Set; +import java.util.function.Predicate; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarInputStream; @@ -90,11 +91,11 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter { * @throws IOException if the entries cannot be written */ public void writeEntries(JarFile jarFile) throws IOException { - writeEntries(jarFile, EntryTransformer.NONE, UnpackHandler.NEVER); + writeEntries(jarFile, EntryTransformer.NONE, UnpackHandler.NEVER, (name) -> false); } - final void writeEntries(JarFile jarFile, EntryTransformer entryTransformer, UnpackHandler unpackHandler) - throws IOException { + final void writeEntries(JarFile jarFile, EntryTransformer entryTransformer, UnpackHandler unpackHandler, + Predicate libraryPredicate) throws IOException { Enumeration entries = jarFile.entries(); while (entries.hasMoreElements()) { JarArchiveEntry entry = new JarArchiveEntry(entries.nextElement()); @@ -103,7 +104,8 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter { EntryWriter entryWriter = new InputStreamEntryWriter(inputStream); JarArchiveEntry transformedEntry = entryTransformer.transform(entry); if (transformedEntry != null) { - writeEntry(transformedEntry, entryWriter, unpackHandler, true); + boolean updateLayerIndex = !libraryPredicate.test(entry.getName()); + writeEntry(transformedEntry, entryWriter, unpackHandler, updateLayerIndex); } } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layout.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layout.java index 8ab82269e5..36d96624dc 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layout.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layout.java @@ -50,6 +50,28 @@ public interface Layout { */ String getClassesLocation(); + /** + * Returns the location of the classpath index file that should be written or + * {@code null} if not index is required. The result should include the filename and + * is relative to the root of the jar. + * @return the classpath index file location + * @since 2.5.0 + */ + default String getClasspathIndexFileLocation() { + return null; + } + + /** + * Returns the location of the layer index file that should be written or {@code null} + * if not index is required. The result should include the filename and is relative to + * the root of the jar. + * @return the layer index file location + * @since 2.5.0 + */ + default String getLayersIndexFileLocation() { + return null; + } + /** * Returns if loader classes should be included to make the archive executable. * @return if the layout is executable diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java index 2dc5af0c86..11d4332b19 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java @@ -160,6 +160,16 @@ public final class Layouts { return "WEB-INF/classes/"; } + @Override + public String getClasspathIndexFileLocation() { + return "WEB-INF/classpath.idx"; + } + + @Override + public String getLayersIndexFileLocation() { + return "WEB-INF/layers.idx"; + } + @Override public boolean isExecutable() { return true; diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Packager.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Packager.java index e0c1dd22ff..5fb17b0e57 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Packager.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Packager.java @@ -172,7 +172,7 @@ public abstract class Packager { } writer.writeManifest(buildManifest(sourceJar)); writeLoaderClasses(writer); - writer.writeEntries(sourceJar, getEntityTransformer(), writeableLibraries); + writer.writeEntries(sourceJar, getEntityTransformer(), writeableLibraries, writeableLibraries::containsEntry); writeableLibraries.write(writer); if (isLayered()) { writeLayerIndex(writer); @@ -190,7 +190,7 @@ public abstract class Packager { } private void writeLayerIndex(AbstractJarWriter writer) throws IOException { - String name = ((RepackagingLayout) this.layout).getLayersIndexFileLocation(); + String name = this.layout.getLayersIndexFileLocation(); if (StringUtils.hasLength(name)) { Layer layer = this.layers.getLayer(name); this.layersIndex.add(layer, name); @@ -318,17 +318,17 @@ public abstract class Packager { private void addBootAttributes(Attributes attributes) { attributes.putValue(BOOT_VERSION_ATTRIBUTE, getClass().getPackage().getImplementationVersion()); - Layout layout = getLayout(); - if (layout instanceof RepackagingLayout) { - addBootBootAttributesForRepackagingLayout(attributes, (RepackagingLayout) layout); - } - else { - addBootBootAttributesForPlainLayout(attributes); - } + addBootAttributesForLayout(attributes); } - private void addBootBootAttributesForRepackagingLayout(Attributes attributes, RepackagingLayout layout) { - attributes.putValue(BOOT_CLASSES_ATTRIBUTE, layout.getRepackagedClassesLocation()); + private void addBootAttributesForLayout(Attributes attributes) { + Layout layout = getLayout(); + if (layout instanceof RepackagingLayout) { + attributes.putValue(BOOT_CLASSES_ATTRIBUTE, ((RepackagingLayout) layout).getRepackagedClassesLocation()); + } + else { + attributes.putValue(BOOT_CLASSES_ATTRIBUTE, layout.getClassesLocation()); + } putIfHasLength(attributes, BOOT_LIB_ATTRIBUTE, getLayout().getLibraryLocation("", LibraryScope.COMPILE)); putIfHasLength(attributes, BOOT_CLASSPATH_INDEX_ATTRIBUTE, layout.getClasspathIndexFileLocation()); if (isLayered()) { @@ -336,11 +336,6 @@ public abstract class Packager { } } - private void addBootBootAttributesForPlainLayout(Attributes attributes) { - attributes.putValue(BOOT_CLASSES_ATTRIBUTE, getLayout().getClassesLocation()); - putIfHasLength(attributes, BOOT_LIB_ATTRIBUTE, getLayout().getLibraryLocation("", LibraryScope.COMPILE)); - } - private void putIfHasLength(Attributes attributes, String name, String value) { if (StringUtils.hasLength(value)) { attributes.putValue(name, value); @@ -348,7 +343,7 @@ public abstract class Packager { } private boolean isLayered() { - return this.layers != null && getLayout() instanceof Layouts.Jar; + return this.layers != null; } /** @@ -466,6 +461,10 @@ public abstract class Packager { return Digest.sha1(library::openStream); } + boolean containsEntry(String name) { + return this.libraries.containsKey(name); + } + private void write(AbstractJarWriter writer) throws IOException { for (Entry entry : this.libraries.entrySet()) { String path = entry.getKey(); @@ -473,12 +472,12 @@ public abstract class Packager { String location = path.substring(0, path.lastIndexOf('/') + 1); writer.writeNestedLibrary(location, library); } - if (getLayout() instanceof RepackagingLayout) { - writeClasspathIndex((RepackagingLayout) getLayout(), writer); + if (Packager.this.layout instanceof RepackagingLayout) { + writeClasspathIndex(getLayout(), writer); } } - private void writeClasspathIndex(RepackagingLayout layout, AbstractJarWriter writer) throws IOException { + private void writeClasspathIndex(Layout layout, AbstractJarWriter writer) throws IOException { List names = this.libraries.keySet().stream().map((path) -> "- \"" + path + "\"") .collect(Collectors.toList()); writer.writeIndexFile(layout.getClasspathIndexFileLocation(), names); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RepackagingLayout.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RepackagingLayout.java index ae49e50b90..992c04887c 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RepackagingLayout.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RepackagingLayout.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -31,26 +31,4 @@ public interface RepackagingLayout extends Layout { */ String getRepackagedClassesLocation(); - /** - * Returns the location of the classpath index file that should be written or - * {@code null} if not index is required. The result should include the filename and - * is relative to the root of the jar. - * @return the classpath index file location - * @since 2.3.0 - */ - default String getClasspathIndexFileLocation() { - return null; - } - - /** - * Returns the location of the layer index file that should be written or {@code null} - * if not index is required. The result should include the filename and is relative to - * the root of the jar. - * @return the layer index file location - * @since 2.3.0 - */ - default String getLayersIndexFileLocation() { - return null; - } - } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/AbstractArchiveIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/AbstractArchiveIntegrationTests.java index b542cff6d3..87991fa694 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/AbstractArchiveIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/AbstractArchiveIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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,15 +16,22 @@ package org.springframework.boot.maven; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.function.Consumer; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.Manifest; import java.util.stream.Stream; +import java.util.zip.ZipEntry; import org.assertj.core.api.AbstractAssert; import org.assertj.core.api.AssertProvider; @@ -60,6 +67,33 @@ abstract class AbstractArchiveIntegrationTests { }; } + protected Map> readLayerIndex(JarFile jarFile) throws IOException { + if (getLayersIndexLocation() == null) { + return Collections.emptyMap(); + } + Map> index = new LinkedHashMap<>(); + ZipEntry indexEntry = jarFile.getEntry(getLayersIndexLocation()); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(jarFile.getInputStream(indexEntry)))) { + String line = reader.readLine(); + String layer = null; + while (line != null) { + if (line.startsWith("- ")) { + layer = line.substring(3, line.length() - 2); + index.put(layer, new ArrayList<>()); + } + else if (line.startsWith(" - ")) { + index.computeIfAbsent(layer, (key) -> new ArrayList<>()).add(line.substring(5, line.length() - 1)); + } + line = reader.readLine(); + } + return index; + } + } + + protected String getLayersIndexLocation() { + return null; + } + static final class JarAssert extends AbstractAssert { private JarAssert(File actual) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java index 0d60105a7f..c85ecc9c88 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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,18 +16,13 @@ package org.springframework.boot.maven; -import java.io.BufferedReader; import java.io.File; import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.jar.JarFile; import java.util.stream.Collectors; -import java.util.zip.ZipEntry; import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.extension.ExtendWith; @@ -47,6 +42,11 @@ import static org.assertj.core.api.Assertions.assertThat; @ExtendWith(MavenBuildExtension.class) class JarIntegrationTests extends AbstractArchiveIntegrationTests { + @Override + protected String getLayersIndexLocation() { + return "BOOT-INF/layers.idx"; + } + @TestTemplate void whenJarIsRepackagedInPlaceOnlyRepackagedJarIsInstalled(MavenBuild mavenBuild) { mavenBuild.project("jar").goals("install").execute((project) -> { @@ -394,24 +394,4 @@ class JarIntegrationTests extends AbstractArchiveIntegrationTests { return jarHash.get(); } - private Map> readLayerIndex(JarFile jarFile) throws IOException { - Map> index = new LinkedHashMap<>(); - ZipEntry indexEntry = jarFile.getEntry("BOOT-INF/layers.idx"); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(jarFile.getInputStream(indexEntry)))) { - String line = reader.readLine(); - String layer = null; - while (line != null) { - if (line.startsWith("- ")) { - layer = line.substring(3, line.length() - 2); - index.put(layer, new ArrayList<>()); - } - else if (line.startsWith(" - ")) { - index.computeIfAbsent(layer, (key) -> new ArrayList<>()).add(line.substring(5, line.length() - 1)); - } - line = reader.readLine(); - } - return index; - } - } - } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/WarIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/WarIntegrationTests.java index 349d76a3e0..d4fc82415b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/WarIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/WarIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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,10 +18,15 @@ package org.springframework.boot.maven; import java.io.File; import java.io.FileReader; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.jar.JarFile; import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.loader.tools.JarModeLibrary; import org.springframework.util.FileCopyUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -34,6 +39,11 @@ import static org.assertj.core.api.Assertions.assertThat; @ExtendWith(MavenBuildExtension.class) class WarIntegrationTests extends AbstractArchiveIntegrationTests { + @Override + protected String getLayersIndexLocation() { + return "WEB-INF/layers.idx"; + } + @TestTemplate void warRepackaging(MavenBuild mavenBuild) { mavenBuild.project("war") @@ -89,4 +99,72 @@ class WarIntegrationTests extends AbstractArchiveIntegrationTests { }); } + @TestTemplate + void repackagedWarContainsTheLayersIndexByDefault(MavenBuild mavenBuild) { + mavenBuild.project("war-layered").execute((project) -> { + File repackaged = new File(project, "war/target/war-layered-0.0.1.BUILD-SNAPSHOT.war"); + assertThat(jar(repackaged)).hasEntryWithNameStartingWith("WEB-INF/classes/") + .hasEntryWithNameStartingWith("WEB-INF/lib/jar-release") + .hasEntryWithNameStartingWith("WEB-INF/lib/jar-snapshot").hasEntryWithNameStartingWith( + "WEB-INF/lib/" + JarModeLibrary.LAYER_TOOLS.getCoordinates().getArtifactId()); + try (JarFile jarFile = new JarFile(repackaged)) { + Map> layerIndex = readLayerIndex(jarFile); + assertThat(layerIndex.keySet()).containsExactly("dependencies", "spring-boot-loader", + "snapshot-dependencies", "application"); + assertThat(layerIndex.get("application")).contains("WEB-INF/lib/jar-release-0.0.1.RELEASE.jar", + "WEB-INF/lib/jar-snapshot-0.0.1.BUILD-SNAPSHOT.jar"); + assertThat(layerIndex.get("dependencies")) + .anyMatch((dependency) -> dependency.startsWith("WEB-INF/lib/spring-context")); + assertThat(layerIndex.get("dependencies")) + .anyMatch((dependency) -> dependency.startsWith("WEB-INF/lib-provided/")); + } + catch (IOException ex) { + } + }); + } + + @TestTemplate + void whenWarIsRepackagedWithTheLayersDisabledDoesNotContainLayersIndex(MavenBuild mavenBuild) { + mavenBuild.project("war-layered-disabled").execute((project) -> { + File repackaged = new File(project, "war/target/war-layered-0.0.1.BUILD-SNAPSHOT.war"); + assertThat(jar(repackaged)).hasEntryWithNameStartingWith("WEB-INF/classes/") + .hasEntryWithNameStartingWith("WEB-INF/lib/jar-release") + .hasEntryWithNameStartingWith("WEB-INF/lib/jar-snapshot") + .doesNotHaveEntryWithName("WEB-INF/layers.idx") + .doesNotHaveEntryWithNameStartingWith("WEB-INF/lib/" + JarModeLibrary.LAYER_TOOLS.getName()); + }); + } + + @TestTemplate + void whenWarIsRepackagedWithTheLayersEnabledAndLayerToolsExcluded(MavenBuild mavenBuild) { + mavenBuild.project("war-layered-no-layer-tools").execute((project) -> { + File repackaged = new File(project, "war/target/war-layered-0.0.1.BUILD-SNAPSHOT.war"); + assertThat(jar(repackaged)).hasEntryWithNameStartingWith("WEB-INF/classes/") + .hasEntryWithNameStartingWith("WEB-INF/lib/jar-release") + .hasEntryWithNameStartingWith("WEB-INF/lib/jar-snapshot") + .hasEntryWithNameStartingWith("WEB-INF/layers.idx") + .doesNotHaveEntryWithNameStartingWith("WEB-INF/lib/" + JarModeLibrary.LAYER_TOOLS.getName()); + }); + } + + @TestTemplate + void whenWarIsRepackagedWithTheCustomLayers(MavenBuild mavenBuild) { + mavenBuild.project("war-layered-custom").execute((project) -> { + File repackaged = new File(project, "war/target/war-layered-0.0.1.BUILD-SNAPSHOT.war"); + assertThat(jar(repackaged)).hasEntryWithNameStartingWith("WEB-INF/classes/") + .hasEntryWithNameStartingWith("WEB-INF/lib/jar-release") + .hasEntryWithNameStartingWith("WEB-INF/lib/jar-snapshot"); + try (JarFile jarFile = new JarFile(repackaged)) { + Map> layerIndex = readLayerIndex(jarFile); + assertThat(layerIndex.keySet()).containsExactly("my-dependencies-name", "snapshot-dependencies", + "configuration", "application"); + assertThat(layerIndex.get("application")) + .contains("WEB-INF/lib/jar-release-0.0.1.RELEASE.jar", + "WEB-INF/lib/jar-snapshot-0.0.1.BUILD-SNAPSHOT.jar", + "WEB-INF/lib/jar-classifier-0.0.1-bravo.jar") + .doesNotContain("WEB-INF/lib/jar-classifier-0.0.1-alpha.jar"); + } + }); + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/jar-classifier/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/jar-classifier/pom.xml new file mode 100644 index 0000000000..509a9fec77 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/jar-classifier/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + org.springframework.boot.maven.it + jar-classifier + 0.0.1 + jar + jar + Classifier Jar dependency + + + + maven-jar-plugin + + + alpha + package + + jar + + + alpha + + + + bravo + package + + jar + + + bravo + + + + + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/jar-release/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/jar-release/pom.xml new file mode 100644 index 0000000000..a06fe545f1 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/jar-release/pom.xml @@ -0,0 +1,11 @@ + + + 4.0.0 + org.springframework.boot.maven.it + jar-release + 0.0.1.RELEASE + jar + jar + Release Jar dependency + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/jar-snapshot/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/jar-snapshot/pom.xml new file mode 100644 index 0000000000..ab31e719ba --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/jar-snapshot/pom.xml @@ -0,0 +1,11 @@ + + + 4.0.0 + org.springframework.boot.maven.it + jar-snapshot + 0.0.1.BUILD-SNAPSHOT + jar + jar + Snapshot Jar dependency + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/pom.xml new file mode 100644 index 0000000000..fe15e8d887 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + org.springframework.boot.maven.it + aggregator + 0.0.1.BUILD-SNAPSHOT + pom + + UTF-8 + @java.version@ + @java.version@ + + + jar-classifier + jar-release + jar-snapshot + war + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/pom.xml new file mode 100644 index 0000000000..1dc04b92c3 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/pom.xml @@ -0,0 +1,76 @@ + + + 4.0.0 + + org.springframework.boot.maven.it + aggregator + 0.0.1.BUILD-SNAPSHOT + + war-layered + war + war + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + repackage + + + + true + ${project.basedir}/src/layers.xml + + + + + + + org.apache.maven.plugins + maven-war-plugin + @maven-war-plugin.version@ + + + + Foo + + + + + + + + + org.springframework + spring-context + @spring-framework.version@ + + + jakarta.servlet + jakarta.servlet-api + @jakarta-servlet.version@ + provided + + + org.springframework.boot.maven.it + jar-snapshot + 0.0.1.BUILD-SNAPSHOT + + + org.springframework.boot.maven.it + jar-classifier + 0.0.1 + bravo + + + org.springframework.boot.maven.it + jar-release + 0.0.1.RELEASE + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/src/layers.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/src/layers.xml new file mode 100644 index 0000000000..c7552b9776 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/src/layers.xml @@ -0,0 +1,26 @@ + + + + **/application*.* + + + + + + + + + *:*:*-SNAPSHOT + + + + + my-dependencies-name + snapshot-dependencies + configuration + application + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/src/main/java/org/test/SampleApplication.java new file mode 100644 index 0000000000..ca2b9a2f0e --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,24 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.test; + +public class SampleApplication { + + public static void main(String[] args) { + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/src/main/webapp/index.html b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/src/main/webapp/index.html new file mode 100644 index 0000000000..18ecdcb795 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/src/main/webapp/index.html @@ -0,0 +1 @@ + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/jar-release/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/jar-release/pom.xml new file mode 100644 index 0000000000..a06fe545f1 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/jar-release/pom.xml @@ -0,0 +1,11 @@ + + + 4.0.0 + org.springframework.boot.maven.it + jar-release + 0.0.1.RELEASE + jar + jar + Release Jar dependency + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/jar-snapshot/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/jar-snapshot/pom.xml new file mode 100644 index 0000000000..ab31e719ba --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/jar-snapshot/pom.xml @@ -0,0 +1,11 @@ + + + 4.0.0 + org.springframework.boot.maven.it + jar-snapshot + 0.0.1.BUILD-SNAPSHOT + jar + jar + Snapshot Jar dependency + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/pom.xml new file mode 100644 index 0000000000..60503bdf68 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + org.springframework.boot.maven.it + aggregator + 0.0.1.BUILD-SNAPSHOT + pom + + UTF-8 + @java.version@ + @java.version@ + + + jar-snapshot + jar-release + war + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/war/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/war/pom.xml new file mode 100644 index 0000000000..eb3041ccc3 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/war/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + + org.springframework.boot.maven.it + aggregator + 0.0.1.BUILD-SNAPSHOT + + war-layered + war + war + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + repackage + + + + false + + + + + + + org.apache.maven.plugins + maven-war-plugin + @maven-war-plugin.version@ + + + + Foo + + + + + + + + + org.springframework + spring-context + @spring-framework.version@ + + + jakarta.servlet + jakarta.servlet-api + @jakarta-servlet.version@ + provided + + + org.springframework.boot.maven.it + jar-snapshot + 0.0.1.BUILD-SNAPSHOT + + + org.springframework.boot.maven.it + jar-release + 0.0.1.RELEASE + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/war/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/war/src/main/java/org/test/SampleApplication.java new file mode 100644 index 0000000000..ca2b9a2f0e --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/war/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,24 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.test; + +public class SampleApplication { + + public static void main(String[] args) { + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/war/src/main/webapp/index.html b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/war/src/main/webapp/index.html new file mode 100644 index 0000000000..18ecdcb795 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/war/src/main/webapp/index.html @@ -0,0 +1 @@ + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/jar-release/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/jar-release/pom.xml new file mode 100644 index 0000000000..a06fe545f1 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/jar-release/pom.xml @@ -0,0 +1,11 @@ + + + 4.0.0 + org.springframework.boot.maven.it + jar-release + 0.0.1.RELEASE + jar + jar + Release Jar dependency + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/jar-snapshot/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/jar-snapshot/pom.xml new file mode 100644 index 0000000000..ab31e719ba --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/jar-snapshot/pom.xml @@ -0,0 +1,11 @@ + + + 4.0.0 + org.springframework.boot.maven.it + jar-snapshot + 0.0.1.BUILD-SNAPSHOT + jar + jar + Snapshot Jar dependency + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/pom.xml new file mode 100644 index 0000000000..60503bdf68 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + org.springframework.boot.maven.it + aggregator + 0.0.1.BUILD-SNAPSHOT + pom + + UTF-8 + @java.version@ + @java.version@ + + + jar-snapshot + jar-release + war + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/war/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/war/pom.xml new file mode 100644 index 0000000000..bc367f75f1 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/war/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + + org.springframework.boot.maven.it + aggregator + 0.0.1.BUILD-SNAPSHOT + + war-layered + war + war + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + repackage + + + + false + + + + + + + org.apache.maven.plugins + maven-war-plugin + @maven-war-plugin.version@ + + + + Foo + + + + + + + + + org.springframework + spring-context + @spring-framework.version@ + + + jakarta.servlet + jakarta.servlet-api + @jakarta-servlet.version@ + provided + + + org.springframework.boot.maven.it + jar-snapshot + 0.0.1.BUILD-SNAPSHOT + + + org.springframework.boot.maven.it + jar-release + 0.0.1.RELEASE + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/war/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/war/src/main/java/org/test/SampleApplication.java new file mode 100644 index 0000000000..ca2b9a2f0e --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/war/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,24 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.test; + +public class SampleApplication { + + public static void main(String[] args) { + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/war/src/main/webapp/index.html b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/war/src/main/webapp/index.html new file mode 100644 index 0000000000..18ecdcb795 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered-no-layer-tools/war/src/main/webapp/index.html @@ -0,0 +1 @@ + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/jar-release/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/jar-release/pom.xml new file mode 100644 index 0000000000..a06fe545f1 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/jar-release/pom.xml @@ -0,0 +1,11 @@ + + + 4.0.0 + org.springframework.boot.maven.it + jar-release + 0.0.1.RELEASE + jar + jar + Release Jar dependency + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/jar-snapshot/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/jar-snapshot/pom.xml new file mode 100644 index 0000000000..ab31e719ba --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/jar-snapshot/pom.xml @@ -0,0 +1,11 @@ + + + 4.0.0 + org.springframework.boot.maven.it + jar-snapshot + 0.0.1.BUILD-SNAPSHOT + jar + jar + Snapshot Jar dependency + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/pom.xml new file mode 100644 index 0000000000..60503bdf68 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + org.springframework.boot.maven.it + aggregator + 0.0.1.BUILD-SNAPSHOT + pom + + UTF-8 + @java.version@ + @java.version@ + + + jar-snapshot + jar-release + war + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/war/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/war/pom.xml new file mode 100644 index 0000000000..f511ce0ced --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/war/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + org.springframework.boot.maven.it + aggregator + 0.0.1.BUILD-SNAPSHOT + + war-layered + war + war + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + repackage + + + + + + org.apache.maven.plugins + maven-war-plugin + @maven-war-plugin.version@ + + + + Foo + + + + + + + + + org.springframework + spring-context + @spring-framework.version@ + + + jakarta.servlet + jakarta.servlet-api + @jakarta-servlet.version@ + provided + + + org.springframework.boot.maven.it + jar-snapshot + 0.0.1.BUILD-SNAPSHOT + + + org.springframework.boot.maven.it + jar-release + 0.0.1.RELEASE + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/war/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/war/src/main/java/org/test/SampleApplication.java new file mode 100644 index 0000000000..ca2b9a2f0e --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/war/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,24 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.test; + +public class SampleApplication { + + public static void main(String[] args) { + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/war/src/main/webapp/index.html b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/war/src/main/webapp/index.html new file mode 100644 index 0000000000..18ecdcb795 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/war-layered/war/src/main/webapp/index.html @@ -0,0 +1 @@ + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractPackagerMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractPackagerMojo.java index a5ad7817b0..84e11ab720 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractPackagerMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractPackagerMojo.java @@ -182,7 +182,10 @@ public abstract class AbstractPackagerMojo extends AbstractDependencyFilterMojo * @throws MojoExecutionException on execution error */ protected final Libraries getLibraries(Collection unpacks) throws MojoExecutionException { - Set artifacts = filterDependencies(this.project.getArtifacts(), getFilters(getAdditionalFilters())); + String packaging = this.project.getPackaging(); + Set projectArtifacts = this.project.getArtifacts(); + Set artifacts = ("war".equals(packaging)) ? projectArtifacts + : filterDependencies(projectArtifacts, getFilters(getAdditionalFilters())); return new ArtifactsLibraries(artifacts, this.session.getProjects(), unpacks, getLog()); }