mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Fix JarFile issues when running on Windows
Fix 'fat jar' support for windows to correctly deal with URL and path slash issues. The root cause of the original problem was caused by JAR URLs not including a root slash (ie `file:C:/Users` vs `file:/C:/Users`) Fixes gh-1145
This commit is contained in:
parent
1f36d4657f
commit
7654259f80
@ -70,7 +70,7 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
|
||||
private final RandomAccessDataFile rootFile;
|
||||
|
||||
private final String name;
|
||||
private final String pathFromRoot;
|
||||
|
||||
private final RandomAccessData data;
|
||||
|
||||
@ -99,32 +99,33 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
* @throws IOException
|
||||
*/
|
||||
JarFile(RandomAccessDataFile file) throws IOException {
|
||||
this(file, file.getFile().getAbsolutePath(), file);
|
||||
this(file, "", file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor used to create a new {@link JarFile} either directly or from a
|
||||
* nested entry.
|
||||
* @param rootFile the root jar file
|
||||
* @param name the name of this file
|
||||
* @param pathFromRoot the name of this file
|
||||
* @param data the underlying data
|
||||
* @throws IOException
|
||||
*/
|
||||
private JarFile(RandomAccessDataFile rootFile, String name, RandomAccessData data)
|
||||
throws IOException {
|
||||
private JarFile(RandomAccessDataFile rootFile, String pathFromRoot,
|
||||
RandomAccessData data) throws IOException {
|
||||
super(rootFile.getFile());
|
||||
CentralDirectoryEndRecord endRecord = new CentralDirectoryEndRecord(data);
|
||||
this.rootFile = rootFile;
|
||||
this.name = name;
|
||||
this.pathFromRoot = pathFromRoot;
|
||||
this.data = getArchiveData(endRecord, data);
|
||||
this.entries = loadJarEntries(endRecord);
|
||||
}
|
||||
|
||||
private JarFile(RandomAccessDataFile rootFile, String name, RandomAccessData data,
|
||||
List<JarEntryData> entries, JarEntryFilter... filters) throws IOException {
|
||||
private JarFile(RandomAccessDataFile rootFile, String pathFromRoot,
|
||||
RandomAccessData data, List<JarEntryData> entries, JarEntryFilter... filters)
|
||||
throws IOException {
|
||||
super(rootFile.getFile());
|
||||
this.rootFile = rootFile;
|
||||
this.name = name;
|
||||
this.pathFromRoot = pathFromRoot;
|
||||
this.data = data;
|
||||
this.entries = filterEntries(entries, filters);
|
||||
}
|
||||
@ -364,7 +365,7 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
return null;
|
||||
}
|
||||
};
|
||||
return new JarFile(this.rootFile, getName() + "!/"
|
||||
return new JarFile(this.rootFile, this.pathFromRoot + "!/"
|
||||
+ sourceEntry.getName().substring(0, sourceName.length() - 1), this.data,
|
||||
this.entries, filter);
|
||||
}
|
||||
@ -375,8 +376,8 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
throw new IllegalStateException("Unable to open nested compressed entry "
|
||||
+ sourceEntry.getName());
|
||||
}
|
||||
return new JarFile(this.rootFile, getName() + "!/" + sourceEntry.getName(),
|
||||
sourceEntry.getData());
|
||||
return new JarFile(this.rootFile, this.pathFromRoot + "!/"
|
||||
+ sourceEntry.getName(), sourceEntry.getData());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -387,7 +388,8 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
*/
|
||||
public synchronized JarFile getFilteredJarFile(JarEntryFilter... filters)
|
||||
throws IOException {
|
||||
return new JarFile(this.rootFile, getName(), this.data, this.entries, filters);
|
||||
return new JarFile(this.rootFile, this.pathFromRoot, this.data, this.entries,
|
||||
filters);
|
||||
}
|
||||
|
||||
private JarEntry getContainedEntry(ZipEntry zipEntry) throws IOException {
|
||||
@ -416,7 +418,7 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
*/
|
||||
public URL getUrl() throws MalformedURLException {
|
||||
Handler handler = new Handler(this);
|
||||
String file = "file:" + getName(PathForm.SYSTEM_INDEPENDENT) + "!/";
|
||||
String file = this.rootFile.getFile().toURI() + this.pathFromRoot + "!/";
|
||||
return new URL("jar", "", -1, file, handler);
|
||||
}
|
||||
|
||||
@ -427,15 +429,8 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getName(PathForm.SYSTEM_DEPENDENT);
|
||||
}
|
||||
|
||||
private String getName(PathForm pathForm) {
|
||||
if (pathForm == PathForm.SYSTEM_INDEPENDENT && File.separatorChar != '/') {
|
||||
return this.name.replace(File.separatorChar, '/');
|
||||
}
|
||||
return this.name;
|
||||
|
||||
String path = this.pathFromRoot;
|
||||
return this.rootFile.getFile() + path;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -463,20 +458,4 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Different forms that paths can be returned.
|
||||
*/
|
||||
private static enum PathForm {
|
||||
|
||||
/**
|
||||
* Use system dependent paths (i.e. include backslashes on Windows)
|
||||
*/
|
||||
SYSTEM_DEPENDENT,
|
||||
|
||||
/**
|
||||
* Use system independent paths (i.e. replace backslashes on Windows)
|
||||
*/
|
||||
SYSTEM_INDEPENDENT
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -113,9 +113,8 @@ public class ExplodedArchiveTests {
|
||||
public void getNestedArchive() throws Exception {
|
||||
Entry entry = getEntriesMap(this.archive).get("nested.jar");
|
||||
Archive nested = this.archive.getNestedArchive(entry);
|
||||
assertThat(nested.getUrl().toString(),
|
||||
equalTo("jar:file:" + this.rootFolder.getPath() + File.separator
|
||||
+ "nested.jar!/"));
|
||||
assertThat(nested.getUrl().toString(), equalTo("jar:" + this.rootFolder.toURI()
|
||||
+ "nested.jar!/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -48,6 +48,8 @@ public class JarFileArchiveTests {
|
||||
|
||||
private JarFileArchive archive;
|
||||
|
||||
private String rootJarFileUrl;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
setup(false);
|
||||
@ -55,6 +57,8 @@ public class JarFileArchiveTests {
|
||||
|
||||
private void setup(boolean unpackNested) throws Exception {
|
||||
this.rootJarFile = this.temporaryFolder.newFile();
|
||||
this.rootJarFileUrl = rootJarFile.toURI().toString();
|
||||
System.out.println(rootJarFileUrl);
|
||||
TestJarCreator.createTestJar(this.rootJarFile, unpackNested);
|
||||
this.archive = new JarFileArchive(this.rootJarFile);
|
||||
}
|
||||
@ -74,7 +78,7 @@ public class JarFileArchiveTests {
|
||||
@Test
|
||||
public void getUrl() throws Exception {
|
||||
URL url = this.archive.getUrl();
|
||||
assertThat(url.toString(), equalTo("jar:file:" + this.rootJarFile.getPath()
|
||||
assertThat(url.toString(), equalTo("jar:" + this.rootJarFileUrl
|
||||
+ "!/"));
|
||||
}
|
||||
|
||||
@ -83,7 +87,7 @@ public class JarFileArchiveTests {
|
||||
Entry entry = getEntriesMap(this.archive).get("nested.jar");
|
||||
Archive nested = this.archive.getNestedArchive(entry);
|
||||
assertThat(nested.getUrl().toString(),
|
||||
equalTo("jar:file:" + this.rootJarFile.getPath() + "!/nested.jar!/"));
|
||||
equalTo("jar:" + this.rootJarFileUrl + "!/nested.jar!/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -97,6 +97,7 @@ public class JarFileTests {
|
||||
assertThat(urlClassLoader.getResource("special/\u00EB.dat"), notNullValue());
|
||||
assertThat(urlClassLoader.getResource("d/9.dat"), notNullValue());
|
||||
jarFile.close();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -180,23 +181,21 @@ public class JarFileTests {
|
||||
@Test
|
||||
public void getUrl() throws Exception {
|
||||
URL url = this.jarFile.getUrl();
|
||||
assertThat(url.toString(), equalTo("jar:file:" + this.rootJarFile.getPath()
|
||||
+ "!/"));
|
||||
assertThat(url.toString(), equalTo("jar:" + this.rootJarFile.toURI() + "!/"));
|
||||
JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
|
||||
assertThat(jarURLConnection.getJarFile(), sameInstance(this.jarFile));
|
||||
assertThat(jarURLConnection.getJarEntry(), nullValue());
|
||||
assertThat(jarURLConnection.getContentLength(), greaterThan(1));
|
||||
assertThat(jarURLConnection.getContent(), sameInstance((Object) this.jarFile));
|
||||
assertThat(jarURLConnection.getContentType(), equalTo("x-java/jar"));
|
||||
assertThat(jarURLConnection.getJarFileURL().toString(), equalTo("file:"
|
||||
+ this.rootJarFile));
|
||||
assertThat(jarURLConnection.getJarFileURL().toURI(),
|
||||
equalTo(this.rootJarFile.toURI()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createEntryUrl() throws Exception {
|
||||
URL url = new URL(this.jarFile.getUrl(), "1.dat");
|
||||
assertThat(url.toString(), equalTo("jar:file:" + this.rootJarFile.getPath()
|
||||
+ "!/1.dat"));
|
||||
assertThat(url.toString(), equalTo("jar:" + this.rootJarFile.toURI() + "!/1.dat"));
|
||||
JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
|
||||
assertThat(jarURLConnection.getJarFile(), sameInstance(this.jarFile));
|
||||
assertThat(jarURLConnection.getJarEntry(),
|
||||
@ -209,7 +208,7 @@ public class JarFileTests {
|
||||
@Test
|
||||
public void getMissingEntryUrl() throws Exception {
|
||||
URL url = new URL(this.jarFile.getUrl(), "missing.dat");
|
||||
assertThat(url.toString(), equalTo("jar:file:" + this.rootJarFile.getPath()
|
||||
assertThat(url.toString(), equalTo("jar:" + this.rootJarFile.toURI()
|
||||
+ "!/missing.dat"));
|
||||
this.thrown.expect(FileNotFoundException.class);
|
||||
((JarURLConnection) url.openConnection()).getJarEntry();
|
||||
@ -251,12 +250,12 @@ public class JarFileTests {
|
||||
assertThat(inputStream.read(), equalTo(-1));
|
||||
|
||||
URL url = nestedJarFile.getUrl();
|
||||
assertThat(url.toString(), equalTo("jar:file:" + this.rootJarFile.getPath()
|
||||
assertThat(url.toString(), equalTo("jar:" + this.rootJarFile.toURI()
|
||||
+ "!/nested.jar!/"));
|
||||
JarURLConnection conn = (JarURLConnection) url.openConnection();
|
||||
assertThat(conn.getJarFile(), sameInstance(nestedJarFile));
|
||||
assertThat(conn.getJarFileURL().toString(), equalTo("jar:file:"
|
||||
+ this.rootJarFile.getPath() + "!/nested.jar"));
|
||||
assertThat(conn.getJarFileURL().toString(),
|
||||
equalTo("jar:" + this.rootJarFile.toURI() + "!/nested.jar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -274,8 +273,7 @@ public class JarFileTests {
|
||||
assertThat(inputStream.read(), equalTo(-1));
|
||||
|
||||
URL url = nestedJarFile.getUrl();
|
||||
assertThat(url.toString(), equalTo("jar:file:" + this.rootJarFile.getPath()
|
||||
+ "!/d!/"));
|
||||
assertThat(url.toString(), equalTo("jar:" + this.rootJarFile.toURI() + "!/d!/"));
|
||||
assertThat(((JarURLConnection) url.openConnection()).getJarFile(),
|
||||
sameInstance(nestedJarFile));
|
||||
}
|
||||
@ -285,7 +283,7 @@ public class JarFileTests {
|
||||
JarFile nestedJarFile = this.jarFile.getNestedJarFile(this.jarFile
|
||||
.getEntry("nested.jar"));
|
||||
URL url = nestedJarFile.getJarEntry("3.dat").getUrl();
|
||||
assertThat(url.toString(), equalTo("jar:file:" + this.rootJarFile.getPath()
|
||||
assertThat(url.toString(), equalTo("jar:" + this.rootJarFile.toURI()
|
||||
+ "!/nested.jar!/3.dat"));
|
||||
InputStream inputStream = url.openStream();
|
||||
assertThat(inputStream, notNullValue());
|
||||
@ -295,7 +293,7 @@ public class JarFileTests {
|
||||
@Test
|
||||
public void createUrlFromString() throws Exception {
|
||||
JarFile.registerUrlProtocolHandler();
|
||||
String spec = "jar:file:" + this.rootJarFile.getPath() + "!/nested.jar!/3.dat";
|
||||
String spec = "jar:" + this.rootJarFile.toURI() + "!/nested.jar!/3.dat";
|
||||
URL url = new URL(spec);
|
||||
assertThat(url.toString(), equalTo(spec));
|
||||
InputStream inputStream = url.openStream();
|
||||
@ -303,15 +301,15 @@ public class JarFileTests {
|
||||
assertThat(inputStream.read(), equalTo(3));
|
||||
JarURLConnection connection = (JarURLConnection) url.openConnection();
|
||||
assertThat(connection.getURL().toString(), equalTo(spec));
|
||||
assertThat(connection.getJarFileURL().toString(), equalTo("jar:file:"
|
||||
+ this.rootJarFile.getPath() + "!/nested.jar"));
|
||||
assertThat(connection.getJarFileURL().toString(), equalTo("jar:"
|
||||
+ this.rootJarFile.toURI() + "!/nested.jar"));
|
||||
assertThat(connection.getEntryName(), equalTo("3.dat"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createNonNestedUrlFromString() throws Exception {
|
||||
JarFile.registerUrlProtocolHandler();
|
||||
String spec = "jar:file:" + this.rootJarFile.getPath() + "!/2.dat";
|
||||
String spec = "jar:" + this.rootJarFile.toURI() + "!/2.dat";
|
||||
URL url = new URL(spec);
|
||||
assertThat(url.toString(), equalTo(spec));
|
||||
InputStream inputStream = url.openStream();
|
||||
@ -319,8 +317,7 @@ public class JarFileTests {
|
||||
assertThat(inputStream.read(), equalTo(2));
|
||||
JarURLConnection connection = (JarURLConnection) url.openConnection();
|
||||
assertThat(connection.getURL().toString(), equalTo(spec));
|
||||
assertThat(connection.getJarFileURL().toString(), equalTo("file:"
|
||||
+ this.rootJarFile.getPath()));
|
||||
assertThat(connection.getJarFileURL().toURI(), equalTo(this.rootJarFile.toURI()));
|
||||
assertThat(connection.getEntryName(), equalTo("2.dat"));
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user