Add group discriminant in case of conflict

Prior to this commit, the repackage goal silently ignored the case of
two libraries having the same name and version but a different group.
As a result, the second library was overwriting the first one in the
repackaged jar.

This commit adds support for custom Library names and updates the
Maven and Gradle plugins so that the name includes the group ID
when there would otherwise be a duplicate.

Fixes gh-1475
This commit is contained in:
Stephane Nicoll
2014-09-03 11:16:49 -07:00
committed by Phillip Webb
parent 449752c9e2
commit f46fe32264
69 changed files with 299 additions and 25 deletions

View File

@@ -128,7 +128,7 @@ public class JarWriter {
public void writeNestedLibrary(String destination, Library library)
throws IOException {
File file = library.getFile();
JarEntry entry = new JarEntry(destination + file.getName());
JarEntry entry = new JarEntry(destination + library.getName());
if (library.isUnpackRequired()) {
entry.setComment("UNPACK:" + FileUtils.sha1Hash(file));
}

View File

@@ -27,6 +27,8 @@ import java.io.File;
*/
public class Library {
private final String name;
private final File file;
private final LibraryScope scope;
@@ -49,11 +51,31 @@ public class Library {
* @param unpackRequired if the library needs to be unpacked before it can be used
*/
public Library(File file, LibraryScope scope, boolean unpackRequired) {
this(null, file, scope, unpackRequired);
}
/**
* Create a new {@link Library}.
* @param name the name of the library as it should be written or {@code null} to use
* the file name
* @param file the source file
* @param scope the scope of the library
* @param unpackRequired if the library needs to be unpacked before it can be used
*/
public Library(String name, File file, LibraryScope scope, boolean unpackRequired) {
this.name = (name == null ? file.getName() : name);
this.file = file;
this.scope = scope;
this.unpackRequired = unpackRequired;
}
/**
* @return the name of file as it should be written
*/
public String getName() {
return this.name;
}
/**
* @return the library file
*/

View File

@@ -20,6 +20,8 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
@@ -153,17 +155,22 @@ public class Repackager {
throws IOException {
final JarWriter writer = new JarWriter(destination);
try {
final Set<String> seen = new HashSet<String>();
writer.writeManifest(buildManifest(sourceJar));
writer.writeEntries(sourceJar);
libraries.doWithLibraries(new LibraryCallback() {
@Override
public void library(Library library) throws IOException {
File file = library.getFile();
if (isZip(file)) {
String destination = Repackager.this.layout
.getLibraryDestination(file.getName(), library.getScope());
.getLibraryDestination(library.getName(),
library.getScope());
if (destination != null) {
if (!seen.add(destination + library.getName())) {
throw new IllegalStateException("Duplicate library "
+ library.getName());
}
writer.writeNestedLibrary(destination, library);
}
}

View File

@@ -299,6 +299,25 @@ public class RepackagerTests {
assertThat(entry.getComment().length(), equalTo(47));
}
@Test
public void duplicateLibraries() throws Exception {
TestJarFile libJar = new TestJarFile(this.temporaryFolder);
libJar.addClass("a/b/C.class", ClassWithoutMainMethod.class);
final File libJarFile = libJar.getFile();
this.testJarFile.addClass("a/b/C.class", ClassWithMainMethod.class);
File file = this.testJarFile.getFile();
Repackager repackager = new Repackager(file);
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("Duplicate library");
repackager.repackage(new Libraries() {
@Override
public void doWithLibraries(LibraryCallback callback) throws IOException {
callback.library(new Library(libJarFile, LibraryScope.COMPILE, false));
callback.library(new Library(libJarFile, LibraryScope.COMPILE, false));
}
});
}
@Test
public void customLayout() throws Exception {
TestJarFile libJar = new TestJarFile(this.temporaryFolder);