Commit 38585bf3 authored by Andy Wilkinson's avatar Andy Wilkinson

Omit any file that is not a zip when repackaging

When repackaging an archive, the files in the resulting lib directory
must be zip files. If they're not zip files, the resulting archive
may fail to run (#324).

The previous approach was to consider an artifact's type when deciding
whether or not it should be packaged. The type is a string and, while
there are a number of well-known values, it can essentially be anything.
This caused a problem with an artifact incorrectly being identified as
being unsuitable for inclusion (#489).

This commit changes the approach. Rather than looking at an artifact's
type, it looks at the first four bytes  of the archive's file. Only if
these header bytes matche that of a zip file is the artifact included.
This is a better match for the requirement that all files in lib be zip
files.

Fixes #489
parent a8ba80bb
...@@ -17,9 +17,7 @@ ...@@ -17,9 +17,7 @@
package org.springframework.boot.gradle.task; package org.springframework.boot.gradle.task;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.gradle.api.Project; import org.gradle.api.Project;
...@@ -37,10 +35,6 @@ import org.springframework.boot.loader.tools.LibraryScope; ...@@ -37,10 +35,6 @@ import org.springframework.boot.loader.tools.LibraryScope;
*/ */
class ProjectLibraries implements Libraries { class ProjectLibraries implements Libraries {
private static final Set<String> SUPPORTED_TYPES = Collections
.unmodifiableSet(new HashSet<String>(Arrays.asList("jar", "ejb",
"ejb-client", "test-jar", "bundle")));
private final Project project; private final Project project;
private String providedConfigurationName = "providedRuntime"; private String providedConfigurationName = "providedRuntime";
...@@ -109,9 +103,7 @@ class ProjectLibraries implements Libraries { ...@@ -109,9 +103,7 @@ class ProjectLibraries implements Libraries {
private void libraries(LibraryScope scope, Set<ResolvedArtifact> artifacts, private void libraries(LibraryScope scope, Set<ResolvedArtifact> artifacts,
LibraryCallback callback) throws IOException { LibraryCallback callback) throws IOException {
for (ResolvedArtifact artifact : artifacts) { for (ResolvedArtifact artifact : artifacts) {
if (SUPPORTED_TYPES.contains(artifact.getType())) { callback.library(artifact.getFile(), scope);
callback.library(artifact.getFile(), scope);
}
} }
} }
} }
...@@ -17,8 +17,10 @@ ...@@ -17,8 +17,10 @@
package org.springframework.boot.loader.tools; package org.springframework.boot.loader.tools;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.jar.Manifest; import java.util.jar.Manifest;
...@@ -33,6 +35,8 @@ import org.springframework.boot.loader.tools.MainClassFinder.ClassNameCallback; ...@@ -33,6 +35,8 @@ import org.springframework.boot.loader.tools.MainClassFinder.ClassNameCallback;
*/ */
public class Repackager { public class Repackager {
private static final byte[] ZIP_FILE_HEADER = new byte[] { 'P', 'K', 3, 4 };
private static final String MAIN_CLASS_ATTRIBUTE = "Main-Class"; private static final String MAIN_CLASS_ATTRIBUTE = "Main-Class";
private static final String START_CLASS_ATTRIBUTE = "Start-Class"; private static final String START_CLASS_ATTRIBUTE = "Start-Class";
...@@ -142,10 +146,37 @@ public class Repackager { ...@@ -142,10 +146,37 @@ public class Repackager {
@Override @Override
public void library(File file, LibraryScope scope) throws IOException { public void library(File file, LibraryScope scope) throws IOException {
String destination = Repackager.this.layout.getLibraryDestination(
file.getName(), scope); if (isZipFile(file)) {
if (destination != null) { String destination = Repackager.this.layout
writer.writeNestedLibrary(destination, file); .getLibraryDestination(file.getName(), scope);
if (destination != null) {
writer.writeNestedLibrary(destination, file);
}
}
}
private boolean isZipFile(File file) {
byte[] buffer = new byte[4];
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
int read = fis.read(buffer);
return (read == 4 && Arrays.equals(buffer, ZIP_FILE_HEADER));
}
catch (IOException ioe) {
return false;
}
finally {
if (fis != null) {
try {
fis.close();
}
catch (IOException ioe) {
// Close quietly
}
}
} }
} }
}); });
......
...@@ -30,6 +30,7 @@ import org.junit.rules.ExpectedException; ...@@ -30,6 +30,7 @@ import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.springframework.boot.loader.tools.sample.ClassWithMainMethod; import org.springframework.boot.loader.tools.sample.ClassWithMainMethod;
import org.springframework.boot.loader.tools.sample.ClassWithoutMainMethod; import org.springframework.boot.loader.tools.sample.ClassWithoutMainMethod;
import org.springframework.util.FileCopyUtils;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
...@@ -256,6 +257,8 @@ public class RepackagerTests { ...@@ -256,6 +257,8 @@ public class RepackagerTests {
TestJarFile libJar = new TestJarFile(this.temporaryFolder); TestJarFile libJar = new TestJarFile(this.temporaryFolder);
libJar.addClass("a/b/C.class", ClassWithoutMainMethod.class); libJar.addClass("a/b/C.class", ClassWithoutMainMethod.class);
final File libJarFile = libJar.getFile(); final File libJarFile = libJar.getFile();
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.addClass("a/b/C.class", ClassWithMainMethod.class);
File file = this.testJarFile.getFile(); File file = this.testJarFile.getFile();
Repackager repackager = new Repackager(file); Repackager repackager = new Repackager(file);
...@@ -263,9 +266,11 @@ public class RepackagerTests { ...@@ -263,9 +266,11 @@ public class RepackagerTests {
@Override @Override
public void doWithLibraries(LibraryCallback callback) throws IOException { public void doWithLibraries(LibraryCallback callback) throws IOException {
callback.library(libJarFile, LibraryScope.COMPILE); callback.library(libJarFile, LibraryScope.COMPILE);
callback.library(libNonJarFile, LibraryScope.COMPILE);
} }
}); });
assertThat(hasEntry(file, "lib/" + libJarFile.getName()), equalTo(true)); assertThat(hasEntry(file, "lib/" + libJarFile.getName()), equalTo(true));
assertThat(hasEntry(file, "lib/" + libNonJarFile.getName()), equalTo(false));
} }
@Test @Test
......
...@@ -17,10 +17,8 @@ ...@@ -17,10 +17,8 @@
package org.springframework.boot.maven; package org.springframework.boot.maven;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
...@@ -33,13 +31,10 @@ import org.springframework.boot.loader.tools.LibraryScope; ...@@ -33,13 +31,10 @@ import org.springframework.boot.loader.tools.LibraryScope;
* {@link Libraries} backed by Maven {@link Artifact}s * {@link Libraries} backed by Maven {@link Artifact}s
* *
* @author Phillip Webb * @author Phillip Webb
* @author Andy Wilkinson
*/ */
public class ArtifactsLibraries implements Libraries { public class ArtifactsLibraries implements Libraries {
private static final Set<String> SUPPORTED_TYPES = Collections
.unmodifiableSet(new HashSet<String>(Arrays.asList("jar", "ejb",
"ejb-client", "test-jar", "bundle")));
private static final Map<String, LibraryScope> SCOPES; private static final Map<String, LibraryScope> SCOPES;
static { static {
Map<String, LibraryScope> scopes = new HashMap<String, LibraryScope>(); Map<String, LibraryScope> scopes = new HashMap<String, LibraryScope>();
...@@ -58,11 +53,9 @@ public class ArtifactsLibraries implements Libraries { ...@@ -58,11 +53,9 @@ public class ArtifactsLibraries implements Libraries {
@Override @Override
public void doWithLibraries(LibraryCallback callback) throws IOException { public void doWithLibraries(LibraryCallback callback) throws IOException {
for (Artifact artifact : this.artifacts) { for (Artifact artifact : this.artifacts) {
if (SUPPORTED_TYPES.contains(artifact.getType())) { LibraryScope scope = SCOPES.get(artifact.getScope());
LibraryScope scope = SCOPES.get(artifact.getScope()); if (scope != null && artifact.getFile() != null) {
if (scope != null && artifact.getFile() != null) { callback.library(artifact.getFile(), scope);
callback.library(artifact.getFile(), scope);
}
} }
} }
} }
......
...@@ -30,7 +30,6 @@ import org.springframework.boot.loader.tools.LibraryScope; ...@@ -30,7 +30,6 @@ import org.springframework.boot.loader.tools.LibraryScope;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
/** /**
* Tests for {@link ArtifactsLibraries}. * Tests for {@link ArtifactsLibraries}.
...@@ -66,13 +65,4 @@ public class ArtifactsLibrariesTest { ...@@ -66,13 +65,4 @@ public class ArtifactsLibrariesTest {
this.libs.doWithLibraries(this.callback); this.libs.doWithLibraries(this.callback);
verify(this.callback).library(this.file, LibraryScope.COMPILE); verify(this.callback).library(this.file, LibraryScope.COMPILE);
} }
@Test
public void doesNotIncludePoms() throws Exception {
given(this.artifact.getType()).willReturn("pom");
given(this.artifact.getScope()).willReturn("compile");
this.libs.doWithLibraries(this.callback);
verifyZeroInteractions(this.callback);
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment