Skip to content

Commit 5e79657

Browse files
committed
Treat URLs for same file in nested archive and from jar root as equal
Consider the following two URLs: jar:file:/test.jar!/BOOT-INF/classes!/foo.txt jar:file:/test.jar!/BOOT-INF/classes/foo.txt They both reference the same foo.txt file in the BOOT-INF/classes directory of test.jar, however the first URL does so via the nested BOOT-INF/classes archive. Previously, this difference in the URLs would lead to PathMatchingResourcePatternResolver returning two resources for foo.txt when asked to find all resources matching the pattern classpath*:/**/*.txt. This commit updates our Handler that is used for jar: URLs to consider the two URLs above to be equivalent such that url1 is equal to url2 and the two urls will produce the same hash code. Closes gh-7449
1 parent a5681c0 commit 5e79657

File tree

2 files changed

+50
-1
lines changed
  • spring-boot-tools/spring-boot-loader/src

2 files changed

+50
-1
lines changed

spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java

+33-1
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,30 @@ private void setFile(URL context, String file) {
196196
setURL(context, JAR_PROTOCOL, null, -1, null, null, file, null, null);
197197
}
198198

199+
@Override
200+
protected int hashCode(URL u) {
201+
int result = 0;
202+
String protocol = u.getProtocol();
203+
if (protocol != null) {
204+
result += protocol.hashCode();
205+
}
206+
String file = u.getFile();
207+
int separatorIndex = file.indexOf(SEPARATOR);
208+
if (separatorIndex == -1) {
209+
return result + file.hashCode();
210+
}
211+
String fileWithoutEntry = file.substring(0, separatorIndex);
212+
try {
213+
result += new URL(fileWithoutEntry).hashCode();
214+
}
215+
catch (MalformedURLException ex) {
216+
result += fileWithoutEntry.hashCode();
217+
}
218+
String entry = canonicalize(file.substring(separatorIndex + 2));
219+
result += entry.hashCode();
220+
return result;
221+
}
222+
199223
@Override
200224
protected boolean sameFile(URL u1, URL u2) {
201225
if (!u1.getProtocol().equals("jar") || !u2.getProtocol().equals("jar")) {
@@ -209,7 +233,11 @@ protected boolean sameFile(URL u1, URL u2) {
209233
String nested1 = u1.getFile().substring(separator1 + SEPARATOR.length());
210234
String nested2 = u2.getFile().substring(separator2 + SEPARATOR.length());
211235
if (!nested1.equals(nested2)) {
212-
return false;
236+
String canonical1 = canonicalize(nested1);
237+
String canonical2 = canonicalize(nested2);
238+
if (!canonical1.equals(canonical2)) {
239+
return false;
240+
}
213241
}
214242
String root1 = u1.getFile().substring(0, separator1);
215243
String root2 = u2.getFile().substring(0, separator2);
@@ -222,6 +250,10 @@ protected boolean sameFile(URL u1, URL u2) {
222250
return super.sameFile(u1, u2);
223251
}
224252

253+
private String canonicalize(String path) {
254+
return path.replace(SEPARATOR, "/");
255+
}
256+
225257
public JarFile getRootJarFileFromUrl(URL url) throws IOException {
226258
String spec = url.getFile();
227259
int separatorIndex = spec.indexOf(SEPARATOR);

spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/HandlerTests.java

+17
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,23 @@ public void sameFileReturnsTrueForSameFileInSameJar() throws MalformedURLExcepti
119119
new URL("jar:file:/the/path/to/the/first.jar!/content.txt"))).isTrue();
120120
}
121121

122+
@Test
123+
public void sameFileReturnsTrueForUrlsThatReferenceSameFileViaNestedArchiveAndFromRootOfJar()
124+
throws MalformedURLException {
125+
assertThat(this.handler.sameFile(
126+
new URL("jar:file:/test.jar!/BOOT-INF/classes!/foo.txt"),
127+
new URL("jar:file:/test.jar!/BOOT-INF/classes/foo.txt"))).isTrue();
128+
}
129+
130+
@Test
131+
public void hashcodesAreEqualForUrlsThatReferenceSameFileViaNestedArchiveAndFromRootOfJar()
132+
throws MalformedURLException {
133+
assertThat(this.handler
134+
.hashCode(new URL("jar:file:/test.jar!/BOOT-INF/classes!/foo.txt")))
135+
.isEqualTo(this.handler.hashCode(
136+
new URL("jar:file:/test.jar!/BOOT-INF/classes/foo.txt")));
137+
}
138+
122139
private URL createUrl(String file) throws MalformedURLException {
123140
return new URL("jar", null, -1, file, this.handler);
124141
}

0 commit comments

Comments
 (0)