Only include zips in BOOT-INF/lib, WEB-INF/lib, and WEB-INF/lib-provided

Closes gh-16001
pull/16343/head
Andy Wilkinson 6 years ago
parent e922cba5e5
commit 59430a2642

@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,6 +16,10 @@
package org.springframework.boot.gradle.tasks.bundling;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
@ -43,6 +47,8 @@ import org.gradle.api.tasks.util.PatternSet;
*/
class BootArchiveSupport {
private static final byte[] ZIP_FILE_HEADER = new byte[] { 'P', 'K', 3, 4 };
private static final Set<String> DEFAULT_LAUNCHER_CLASSES;
static {
@ -120,6 +126,26 @@ class BootArchiveSupport {
configureExclusions();
}
boolean isZip(File file) {
try {
try (FileInputStream fileInputStream = new FileInputStream(file)) {
return isZip(fileInputStream);
}
}
catch (IOException ex) {
return false;
}
}
private boolean isZip(InputStream inputStream) throws IOException {
for (int i = 0; i < ZIP_FILE_HEADER.length; i++) {
if (inputStream.read() != ZIP_FILE_HEADER[i]) {
return false;
}
}
return true;
}
private void configureExclusions() {
Set<String> excludes = new HashSet<>();
if (this.excludeDevtools) {

@ -58,6 +58,13 @@ public class BootJar extends Jar implements BootArchive {
this.bootInf.filesMatching("module-info.class", (details) -> {
details.setRelativePath(details.getRelativeSourcePath());
});
getRootSpec().eachFile((details) -> {
String pathString = details.getRelativePath().getPathString();
if (pathString.startsWith("BOOT-INF/lib/")
&& !this.support.isZip(details.getFile())) {
details.exclude();
}
});
}
private Action<CopySpec> classpathFiles(Spec<File> filter) {

@ -57,6 +57,14 @@ public class BootWar extends War implements BootArchive {
getRootSpec().filesMatching("module-info.class", (details) -> {
details.setRelativePath(details.getRelativeSourcePath());
});
getRootSpec().eachFile((details) -> {
String pathString = details.getRelativePath().getPathString();
if ((pathString.startsWith("WEB-INF/lib/")
|| pathString.startsWith("WEB-INF/lib-provided/"))
&& !this.support.isZip(details.getFile())) {
details.exclude();
}
});
}
@Override

@ -17,11 +17,15 @@
package org.springframework.boot.gradle.docs;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import org.junit.Rule;
import org.junit.Test;
@ -108,8 +112,8 @@ public class PackagingDocumentationTests {
@Test
public void bootWarIncludeDevtools() throws IOException {
new File(this.gradleBuild.getProjectDir(),
"spring-boot-devtools-1.2.3.RELEASE.jar").createNewFile();
jarFile(new File(this.gradleBuild.getProjectDir(),
"spring-boot-devtools-1.2.3.RELEASE.jar"));
this.gradleBuild.script("src/main/gradle/packaging/boot-war-include-devtools")
.build("bootWar");
File file = new File(this.gradleBuild.getProjectDir(),
@ -196,7 +200,14 @@ public class PackagingDocumentationTests {
File bootJar = new File(this.gradleBuild.getProjectDir(),
"build/libs/" + this.gradleBuild.getProjectDir().getName() + "-boot.jar");
assertThat(bootJar).isFile();
}
protected void jarFile(File file) throws IOException {
try (JarOutputStream jar = new JarOutputStream(new FileOutputStream(file))) {
jar.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
new Manifest().write(jar);
jar.closeEntry();
}
}
}

@ -17,6 +17,7 @@
package org.springframework.boot.gradle.tasks.bundling;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
@ -30,6 +31,9 @@ import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
@ -108,7 +112,7 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
@Test
public void classpathJarsArePackagedBeneathLibPath() throws IOException {
this.task.setMainClassName("com.example.Main");
this.task.classpath(this.temp.newFile("one.jar"), this.temp.newFile("two.jar"));
this.task.classpath(jarFile("one.jar"), jarFile("two.jar"));
this.task.execute();
try (JarFile jarFile = new JarFile(this.task.getArchivePath())) {
assertThat(jarFile.getEntry(this.libPath + "/one.jar")).isNotNull();
@ -160,9 +164,8 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
@Test
public void classpathCanBeSetUsingAFileCollection() throws IOException {
this.task.setMainClassName("com.example.Main");
this.task.classpath(this.temp.newFile("one.jar"));
this.task
.setClasspath(this.task.getProject().files(this.temp.newFile("two.jar")));
this.task.classpath(jarFile("one.jar"));
this.task.setClasspath(this.task.getProject().files(jarFile("two.jar")));
this.task.execute();
try (JarFile jarFile = new JarFile(this.task.getArchivePath())) {
assertThat(jarFile.getEntry(this.libPath + "/one.jar")).isNull();
@ -173,8 +176,8 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
@Test
public void classpathCanBeSetUsingAnObject() throws IOException {
this.task.setMainClassName("com.example.Main");
this.task.classpath(this.temp.newFile("one.jar"));
this.task.setClasspath(this.temp.newFile("two.jar"));
this.task.classpath(jarFile("one.jar"));
this.task.setClasspath(jarFile("two.jar"));
this.task.execute();
try (JarFile jarFile = new JarFile(this.task.getArchivePath())) {
assertThat(jarFile.getEntry(this.libPath + "/one.jar")).isNull();
@ -182,6 +185,16 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
}
}
@Test
public void filesOnTheClasspathThatAreNotZipFilesAreSkipped() throws IOException {
this.task.setMainClassName("com.example.Main");
this.task.classpath(this.temp.newFile("test.pom"));
this.task.execute();
try (JarFile jarFile = new JarFile(this.task.getArchivePath())) {
assertThat(jarFile.getEntry(this.libPath + "/test.pom")).isNull();
}
}
@Test
public void loaderIsWrittenToTheRootOfTheJar() throws IOException {
this.task.setMainClassName("com.example.Main");
@ -212,7 +225,7 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
@Test
public void unpackCommentIsAddedToEntryIdentifiedByAPattern() throws IOException {
this.task.setMainClassName("com.example.Main");
this.task.classpath(this.temp.newFile("one.jar"), this.temp.newFile("two.jar"));
this.task.classpath(jarFile("one.jar"), jarFile("two.jar"));
this.task.requiresUnpack("**/one.jar");
this.task.execute();
try (JarFile jarFile = new JarFile(this.task.getArchivePath())) {
@ -225,7 +238,7 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
@Test
public void unpackCommentIsAddedToEntryIdentifiedByASpec() throws IOException {
this.task.setMainClassName("com.example.Main");
this.task.classpath(this.temp.newFile("one.jar"), this.temp.newFile("two.jar"));
this.task.classpath(jarFile("one.jar"), jarFile("two.jar"));
this.task.requiresUnpack((element) -> element.getName().endsWith("two.jar"));
this.task.execute();
try (JarFile jarFile = new JarFile(this.task.getArchivePath())) {
@ -370,7 +383,7 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
@Test
public void devtoolsJarCanBeIncluded() throws IOException {
this.task.setMainClassName("com.example.Main");
this.task.classpath(this.temp.newFile("spring-boot-devtools-0.1.2.jar"));
this.task.classpath(jarFile("spring-boot-devtools-0.1.2.jar"));
this.task.setExcludeDevtools(false);
this.task.execute();
assertThat(this.task.getArchivePath()).exists();
@ -410,9 +423,8 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
"com/example/Application.class");
applicationClass.getParentFile().mkdirs();
applicationClass.createNewFile();
this.task.classpath(classpathFolder, this.temp.newFile("first-library.jar"),
this.temp.newFile("second-library.jar"),
this.temp.newFile("third-library.jar"));
this.task.classpath(classpathFolder, jarFile("first-library.jar"),
jarFile("second-library.jar"), jarFile("third-library.jar"));
this.task.requiresUnpack("second-library.jar");
this.task.execute();
assertThat(getEntryNames(this.task.getArchivePath())).containsSubsequence(
@ -422,6 +434,16 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
this.libPath + "/third-library.jar");
}
protected File jarFile(String name) throws IOException {
File file = this.temp.newFile(name);
try (JarOutputStream jar = new JarOutputStream(new FileOutputStream(file))) {
jar.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
new Manifest().write(jar);
jar.closeEntry();
}
return file;
}
private T configure(T task) throws IOException {
AbstractArchiveTask archiveTask = task;
archiveTask.setBaseName("test");

@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -39,8 +39,7 @@ public class BootWarTests extends AbstractBootArchiveTests<BootWar> {
@Test
public void providedClasspathJarsArePackagedInWebInfLibProvided() throws IOException {
getTask().setMainClassName("com.example.Main");
getTask().providedClasspath(this.temp.newFile("one.jar"),
this.temp.newFile("two.jar"));
getTask().providedClasspath(jarFile("one.jar"), jarFile("two.jar"));
getTask().execute();
try (JarFile jarFile = new JarFile(getTask().getArchivePath())) {
assertThat(jarFile.getEntry("WEB-INF/lib-provided/one.jar")).isNotNull();
@ -51,9 +50,8 @@ public class BootWarTests extends AbstractBootArchiveTests<BootWar> {
@Test
public void providedClasspathCanBeSetUsingAFileCollection() throws IOException {
getTask().setMainClassName("com.example.Main");
getTask().providedClasspath(this.temp.newFile("one.jar"));
getTask().setProvidedClasspath(
getTask().getProject().files(this.temp.newFile("two.jar")));
getTask().providedClasspath(jarFile("one.jar"));
getTask().setProvidedClasspath(getTask().getProject().files(jarFile("two.jar")));
getTask().execute();
try (JarFile jarFile = new JarFile(getTask().getArchivePath())) {
assertThat(jarFile.getEntry("WEB-INF/lib-provided/one.jar")).isNull();
@ -64,8 +62,8 @@ public class BootWarTests extends AbstractBootArchiveTests<BootWar> {
@Test
public void providedClasspathCanBeSetUsingAnObject() throws IOException {
getTask().setMainClassName("com.example.Main");
getTask().providedClasspath(this.temp.newFile("one.jar"));
getTask().setProvidedClasspath(this.temp.newFile("two.jar"));
getTask().providedClasspath(jarFile("one.jar"));
getTask().setProvidedClasspath(jarFile("two.jar"));
getTask().execute();
try (JarFile jarFile = new JarFile(getTask().getArchivePath())) {
assertThat(jarFile.getEntry("WEB-INF/lib-provided/one.jar")).isNull();
@ -91,7 +89,7 @@ public class BootWarTests extends AbstractBootArchiveTests<BootWar> {
public void devtoolsJarCanBeIncludedWhenItsOnTheProvidedClasspath()
throws IOException {
getTask().setMainClassName("com.example.Main");
getTask().providedClasspath(this.temp.newFile("spring-boot-devtools-0.1.2.jar"));
getTask().providedClasspath(jarFile("spring-boot-devtools-0.1.2.jar"));
getTask().setExcludeDevtools(false);
getTask().execute();
assertThat(getTask().getArchivePath()).exists();
@ -122,8 +120,8 @@ public class BootWarTests extends AbstractBootArchiveTests<BootWar> {
@Test
public void libProvidedEntriesAreWrittenAfterLibEntries() throws IOException {
getTask().setMainClassName("com.example.Main");
getTask().classpath(this.temp.newFile("library.jar"));
getTask().providedClasspath(this.temp.newFile("provided-library.jar"));
getTask().classpath(jarFile("library.jar"));
getTask().providedClasspath(jarFile("provided-library.jar"));
getTask().execute();
assertThat(getEntryNames(getTask().getArchivePath())).containsSubsequence(
"WEB-INF/lib/library.jar", "WEB-INF/lib-provided/provided-library.jar");

Loading…
Cancel
Save