Restore check for jar root existence (now via getEntryName/getJarEntry)
Closes gh-34607
This commit is contained in:
parent
5b6abe4c13
commit
760376c318
|
@ -56,6 +56,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
|
||||||
// Try a URL connection content-length header
|
// Try a URL connection content-length header
|
||||||
URLConnection con = url.openConnection();
|
URLConnection con = url.openConnection();
|
||||||
customizeConnection(con);
|
customizeConnection(con);
|
||||||
|
|
||||||
HttpURLConnection httpCon = (con instanceof HttpURLConnection huc ? huc : null);
|
HttpURLConnection httpCon = (con instanceof HttpURLConnection huc ? huc : null);
|
||||||
if (httpCon != null) {
|
if (httpCon != null) {
|
||||||
httpCon.setRequestMethod("HEAD");
|
httpCon.setRequestMethod("HEAD");
|
||||||
|
@ -81,12 +82,16 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check content-length entry but not for JarURLConnection where
|
|
||||||
// this would open the jar file but effectively never close it ->
|
if (con instanceof JarURLConnection jarCon) {
|
||||||
// for jar entries, always fall back to stream existence instead.
|
// For JarURLConnection, do not check content-length but rather the
|
||||||
if (!(con instanceof JarURLConnection) && con.getContentLengthLong() > 0) {
|
// existence of the entry (or the jar root in case of no entryName).
|
||||||
|
return (jarCon.getEntryName() == null || jarCon.getJarEntry() != null);
|
||||||
|
}
|
||||||
|
else if (con.getContentLengthLong() > 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (httpCon != null) {
|
if (httpCon != null) {
|
||||||
// No HTTP OK status, and no content-length header: give up
|
// No HTTP OK status, and no content-length header: give up
|
||||||
httpCon.disconnect();
|
httpCon.disconnect();
|
||||||
|
@ -346,8 +351,8 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
|
||||||
*/
|
*/
|
||||||
protected void customizeConnection(URLConnection con) throws IOException {
|
protected void customizeConnection(URLConnection con) throws IOException {
|
||||||
ResourceUtils.useCachesIfNecessary(con);
|
ResourceUtils.useCachesIfNecessary(con);
|
||||||
if (con instanceof HttpURLConnection httpConn) {
|
if (con instanceof HttpURLConnection httpCon) {
|
||||||
customizeConnection(httpConn);
|
customizeConnection(httpCon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2024 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -234,8 +234,8 @@ public class UrlResource extends AbstractFileResolvingResource {
|
||||||
}
|
}
|
||||||
catch (IOException ex) {
|
catch (IOException ex) {
|
||||||
// Close the HTTP connection (if applicable).
|
// Close the HTTP connection (if applicable).
|
||||||
if (con instanceof HttpURLConnection httpConn) {
|
if (con instanceof HttpURLConnection httpCon) {
|
||||||
httpConn.disconnect();
|
httpCon.disconnect();
|
||||||
}
|
}
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,8 +51,10 @@ import org.junit.jupiter.api.io.TempDir;
|
||||||
import org.springframework.core.io.DefaultResourceLoader;
|
import org.springframework.core.io.DefaultResourceLoader;
|
||||||
import org.springframework.core.io.FileSystemResource;
|
import org.springframework.core.io.FileSystemResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.UrlResource;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.FileSystemUtils;
|
import org.springframework.util.FileSystemUtils;
|
||||||
|
import org.springframework.util.ResourceUtils;
|
||||||
import org.springframework.util.StreamUtils;
|
import org.springframework.util.StreamUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
@ -133,6 +135,7 @@ class PathMatchingResourcePatternResolverTests {
|
||||||
assertExactFilenames("classpath*:scanned/*.txt", "resource#test1.txt", "resource#test2.txt");
|
assertExactFilenames("classpath*:scanned/*.txt", "resource#test1.txt", "resource#test2.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
class WithHashtagsInTheirFilenames {
|
class WithHashtagsInTheirFilenames {
|
||||||
|
|
||||||
|
@ -299,6 +302,7 @@ class PathMatchingResourcePatternResolverTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
class ClassPathManifestEntries {
|
class ClassPathManifestEntries {
|
||||||
|
|
||||||
|
@ -313,8 +317,8 @@ class PathMatchingResourcePatternResolverTests {
|
||||||
writeApplicationJar(this.temp.resolve("app.jar"));
|
writeApplicationJar(this.temp.resolve("app.jar"));
|
||||||
String java = ProcessHandle.current().info().command().get();
|
String java = ProcessHandle.current().info().command().get();
|
||||||
Process process = new ProcessBuilder(java, "-jar", "app.jar")
|
Process process = new ProcessBuilder(java, "-jar", "app.jar")
|
||||||
.directory(this.temp.toFile())
|
.directory(this.temp.toFile())
|
||||||
.start();
|
.start();
|
||||||
assertThat(process.waitFor()).isZero();
|
assertThat(process.waitFor()).isZero();
|
||||||
String result = StreamUtils.copyToString(process.getInputStream(), StandardCharsets.UTF_8);
|
String result = StreamUtils.copyToString(process.getInputStream(), StandardCharsets.UTF_8);
|
||||||
assertThat(result.replace("\\", "/")).contains("!!!!").contains("/lib/asset.jar!/assets/file.txt");
|
assertThat(result.replace("\\", "/")).contains("!!!!").contains("/lib/asset.jar!/assets/file.txt");
|
||||||
|
@ -328,6 +332,8 @@ class PathMatchingResourcePatternResolverTests {
|
||||||
StreamUtils.copy("test", StandardCharsets.UTF_8, jar);
|
StreamUtils.copy("test", StandardCharsets.UTF_8, jar);
|
||||||
jar.closeEntry();
|
jar.closeEntry();
|
||||||
}
|
}
|
||||||
|
assertThat(new FileSystemResource(path).exists()).isTrue();
|
||||||
|
assertThat(new UrlResource(ResourceUtils.JAR_URL_PREFIX + ResourceUtils.FILE_URL_PREFIX + path + ResourceUtils.JAR_URL_SEPARATOR).exists()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeApplicationJar(Path path) throws Exception {
|
private void writeApplicationJar(Path path) throws Exception {
|
||||||
|
@ -338,8 +344,7 @@ class PathMatchingResourcePatternResolverTests {
|
||||||
mainAttributes.put(Name.MANIFEST_VERSION, "1.0");
|
mainAttributes.put(Name.MANIFEST_VERSION, "1.0");
|
||||||
try (JarOutputStream jar = new JarOutputStream(new FileOutputStream(path.toFile()), manifest)) {
|
try (JarOutputStream jar = new JarOutputStream(new FileOutputStream(path.toFile()), manifest)) {
|
||||||
String appClassResource = ClassUtils.convertClassNameToResourcePath(
|
String appClassResource = ClassUtils.convertClassNameToResourcePath(
|
||||||
ClassPathManifestEntriesTestApplication.class.getName())
|
ClassPathManifestEntriesTestApplication.class.getName()) + ClassUtils.CLASS_FILE_SUFFIX;
|
||||||
+ ClassUtils.CLASS_FILE_SUFFIX;
|
|
||||||
String folder = "";
|
String folder = "";
|
||||||
for (String name : appClassResource.split("/")) {
|
for (String name : appClassResource.split("/")) {
|
||||||
if (!name.endsWith(ClassUtils.CLASS_FILE_SUFFIX)) {
|
if (!name.endsWith(ClassUtils.CLASS_FILE_SUFFIX)) {
|
||||||
|
@ -356,18 +361,19 @@ class PathMatchingResourcePatternResolverTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
assertThat(new FileSystemResource(path).exists()).isTrue();
|
||||||
|
assertThat(new UrlResource(ResourceUtils.JAR_URL_PREFIX + ResourceUtils.FILE_URL_PREFIX + path + ResourceUtils.JAR_URL_SEPARATOR).exists()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildSpringClassPath() throws Exception {
|
private String buildSpringClassPath() throws Exception {
|
||||||
return copyClasses(PathMatchingResourcePatternResolver.class, "spring-core")
|
return copyClasses(PathMatchingResourcePatternResolver.class, "spring-core") +
|
||||||
+ copyClasses(LogFactory.class, "commons-logging");
|
copyClasses(LogFactory.class, "commons-logging");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String copyClasses(Class<?> sourceClass, String destinationName)
|
private String copyClasses(Class<?> sourceClass, String destinationName) throws URISyntaxException, IOException {
|
||||||
throws URISyntaxException, IOException {
|
|
||||||
Path destination = this.temp.resolve(destinationName);
|
Path destination = this.temp.resolve(destinationName);
|
||||||
String resourcePath = ClassUtils.convertClassNameToResourcePath(sourceClass.getName())
|
String resourcePath = ClassUtils.convertClassNameToResourcePath(
|
||||||
+ ClassUtils.CLASS_FILE_SUFFIX;
|
sourceClass.getName()) + ClassUtils.CLASS_FILE_SUFFIX;
|
||||||
URL resource = getClass().getClassLoader().getResource(resourcePath);
|
URL resource = getClass().getClassLoader().getResource(resourcePath);
|
||||||
URL url = new URL(resource.toString().replace(resourcePath, ""));
|
URL url = new URL(resource.toString().replace(resourcePath, ""));
|
||||||
URLConnection connection = url.openConnection();
|
URLConnection connection = url.openConnection();
|
||||||
|
@ -393,7 +399,6 @@ class PathMatchingResourcePatternResolverTests {
|
||||||
}
|
}
|
||||||
return destinationName + "/ ";
|
return destinationName + "/ ";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue