Make JAR files on classpath a special case for archive

If the user adds a JAR file to the classpath in "spring jar -cp ..."
he expected it to end up in the classpath of the executable jar
(i.e. in the nested lib/ directory). Before this change it would
have gone in the root of the executable JAR, causing errors at runtime.

The fix is slightly awkward, since it assumes that any JAR in the
"roots" of the ResourceMatcher come from the classpath (which *is*
the case currently, but might not always be at least in principle).
Seems like a reasonable compromise given it's a quick change
and some tests have been included.

Fixes gh-565
This commit is contained in:
Dave Syer 2014-03-25 11:36:24 +00:00
parent a821092bbd
commit 60fe468af9
3 changed files with 59 additions and 3 deletions

View File

@ -155,9 +155,11 @@ public class JarCommand extends OptionParsingCommand {
options.valuesOf(this.excludeOption));
List<File> roots = new ArrayList<File>();
for (URL classpathEntry : classpath) {
roots.add(new File(URI.create(classpathEntry.toString())));
File file = new File(URI.create(classpathEntry.toString()));
roots.add(file);
}
return matcher.find(roots);
List<MatchedResource> found = matcher.find(roots);
return found;
}
private void writeJar(File file, Class<?>[] compiledClasses,

View File

@ -147,7 +147,7 @@ class ResourceMatcher {
private MatchedResource(File file) {
this.name = file.getName();
this.file = file;
this.root = false;
this.root = this.name.endsWith(".jar");
}
private MatchedResource(File rootFolder, File file) {

View File

@ -22,10 +22,15 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Test;
import org.springframework.boot.cli.command.jar.ResourceMatcher.MatchedResource;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
@ -45,6 +50,27 @@ public class ResourceMatcherTests {
assertEquals(0, matchedResources.size());
}
@Test
public void excludedWins() throws Exception {
ResourceMatcher resourceMatcher = new ResourceMatcher(Arrays.asList("*"),
Arrays.asList("**/*.jar"));
List<MatchedResource> found = resourceMatcher.find(Arrays.asList(new File(
"src/test/resources")));
assertThat(found, not(hasItem(new FooJarMatcher(MatchedResource.class))));
}
@Test
public void jarFileAlwaysMatches() throws Exception {
ResourceMatcher resourceMatcher = new ResourceMatcher(Arrays.asList("*"),
Arrays.asList("**/*.jar"));
List<MatchedResource> found = resourceMatcher.find(Arrays.asList(new File(
"src/test/resources/templates"), new File("src/test/resources/foo.jar")));
FooJarMatcher matcher = new FooJarMatcher(MatchedResource.class);
assertThat(found, hasItem(matcher));
// A jar file is always treated as a dependency (stick it in /lib)
assertTrue(matcher.getMatched().isRoot());
}
@Test
public void resourceMatching() throws IOException {
List<MatchedResource> matchedResources = this.resourceMatcher.find(Arrays.asList(
@ -61,4 +87,32 @@ public class ResourceMatcherTests {
assertTrue(paths.containsAll(Arrays.asList("alpha/nested/fileA", "bravo/fileC",
"fileD", "bravo/fileE", "fileF", "three")));
}
private final class FooJarMatcher extends TypeSafeMatcher<MatchedResource> {
private MatchedResource matched;
public MatchedResource getMatched() {
return this.matched;
}
private FooJarMatcher(Class<?> expectedType) {
super(expectedType);
}
@Override
public void describeTo(Description description) {
description.appendText("foo.jar");
}
@Override
protected boolean matchesSafely(MatchedResource item) {
boolean matches = item.getFile().getName().equals("foo.jar");
if (matches) {
this.matched = item;
}
return matches;
}
}
}