diff --git a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java index 69c72b66072..5bb1185dcf4 100644 --- a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java @@ -20,6 +20,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.net.HttpURLConnection; +import java.net.JarURLConnection; import java.net.URI; import java.net.URL; import java.net.URLConnection; @@ -27,6 +28,7 @@ import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; import java.nio.file.NoSuchFileException; import java.nio.file.StandardOpenOption; +import java.util.jar.JarEntry; import org.springframework.util.ResourceUtils; @@ -115,6 +117,16 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { return false; } } + else if (con instanceof JarURLConnection) { + JarURLConnection jarCon = (JarURLConnection) con; + JarEntry jarEntry = jarCon.getJarEntry(); + if (jarEntry == null) { + return false; + } + else { + return !jarEntry.isDirectory(); + } + } long contentLength = con.getContentLengthLong(); if (contentLength > 0) { return true; diff --git a/spring-core/src/test/java/org/springframework/core/io/ClassPathResourceTests.java b/spring-core/src/test/java/org/springframework/core/io/ClassPathResourceTests.java index 78c72bd0488..9d29938fdfb 100644 --- a/spring-core/src/test/java/org/springframework/core/io/ClassPathResourceTests.java +++ b/spring-core/src/test/java/org/springframework/core/io/ClassPathResourceTests.java @@ -16,10 +16,18 @@ package org.springframework.core.io; +import java.io.File; import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -143,4 +151,32 @@ class ClassPathResourceTests { assertThat(jarDir.isReadable()).isFalse(); } + @Test + void emptyFileReadable(@TempDir File tempDir) throws IOException { + File file = new File(tempDir, "empty.txt"); + assertThat(file.createNewFile()).isTrue(); + assertThat(file.isFile()); + + ClassLoader fileClassLoader = new URLClassLoader(new URL[]{tempDir.toURI().toURL()}); + + Resource emptyFile = new ClassPathResource("empty.txt", fileClassLoader); + assertThat(emptyFile.exists()).isTrue(); + assertThat(emptyFile.isReadable()).isTrue(); + assertThat(emptyFile.contentLength()).isEqualTo(0); + + File jarFile = new File(tempDir, "test.jar"); + try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(jarFile))) { + zipOut.putNextEntry(new ZipEntry("empty2.txt")); + zipOut.closeEntry(); + } + assertThat(jarFile.isFile()); + + ClassLoader jarClassLoader = new URLClassLoader(new URL[]{jarFile.toURI().toURL()}); + + Resource emptyJarEntry = new ClassPathResource("empty2.txt", jarClassLoader); + assertThat(emptyJarEntry.exists()).isTrue(); + assertThat(emptyJarEntry.isReadable()).isTrue(); + assertThat(emptyJarEntry.contentLength()).isEqualTo(0); + } + }