From 14d0c28713e3713d6f04c80ace0d91682ad3f3a6 Mon Sep 17 00:00:00 2001 From: lprimak Date: Thu, 21 May 2026 04:07:08 -0500 Subject: [PATCH 1/3] bugfix(3.x): restore resource loading file:// and relative path functionality --- .../apache/shiro/lang/io/ResourceUtils.java | 6 ++++-- .../apache/shiro/lang/util/ClassUtilsTest.java | 18 ++++++++++++++++-- lang/src/test/resources/test-data/file.json | 1 + 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 lang/src/test/resources/test-data/file.json diff --git a/lang/src/main/java/org/apache/shiro/lang/io/ResourceUtils.java b/lang/src/main/java/org/apache/shiro/lang/io/ResourceUtils.java index b7c241cc1f..08f95688d4 100644 --- a/lang/src/main/java/org/apache/shiro/lang/io/ResourceUtils.java +++ b/lang/src/main/java/org/apache/shiro/lang/io/ResourceUtils.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.nio.file.Paths; /** * Static helper methods for loading {@code Stream}-backed resources. @@ -120,7 +121,6 @@ public static boolean resourceExists(String resourcePath) { * @throws IOException if there is a problem acquiring the resource at the specified path. */ public static InputStream getInputStreamForPath(String resourcePath) throws IOException { - URL url = getURLForPath(resourcePath); if (url == null) { throw new IOException("Resource [" + resourcePath + "] could not be found."); @@ -148,8 +148,10 @@ public static URL getURLForPath(String resourcePath) throws IOException { url = ClassUtils.getResource(stripPrefix(resourcePath)); } else if (resourcePath.startsWith(URL_PREFIX)) { url = URI.create(stripPrefix(resourcePath)).toURL(); + } else if (resourcePath.startsWith(FILE_PREFIX)) { + url = Paths.get(stripPrefix(resourcePath)).toUri().toURL(); } else { - url = URI.create(resourcePath).toURL(); + url = Paths.get(resourcePath).toUri().toURL(); } if (url == null) { diff --git a/lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java b/lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java index e1988276ee..2ab783e998 100644 --- a/lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java +++ b/lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java @@ -20,13 +20,14 @@ import org.junit.jupiter.api.Test; +import java.io.IOException; +import java.io.InputStream; +import static org.apache.shiro.lang.io.ResourceUtils.getInputStreamForPath; import static org.assertj.core.api.Assertions.assertThat; class ClassUtilsTest { - @Test void testGetPrimitiveClasses() throws UnknownClassException { - assertThat(ClassUtils.forName("boolean")).isEqualTo(boolean.class); assertThat(ClassUtils.forName("byte")).isEqualTo(byte.class); assertThat(ClassUtils.forName("char")).isEqualTo(char.class); @@ -84,4 +85,17 @@ void testGetClass() { assertThat(ClassUtils.forName(ClassUtilsTest.class.getName())).isEqualTo(ClassUtilsTest.class); assertThat(ClassUtils.forName(ClassUtilsTest[].class.getName())).isEqualTo(ClassUtilsTest[].class); } + + @Test + void inputStream() throws IOException { + try (InputStream is = getInputStreamForPath("classpath:org/apache/shiro/lang/util/ClassUtilsTest.class")) { + assertThat(is.readAllBytes()).isNotEmpty(); + } + try (InputStream is = getInputStreamForPath("target/test-classes/test-data/file.json")) { + assertThat(is.readAllBytes()).isNotEmpty(); + } + try (InputStream is = getInputStreamForPath("file:target/test-classes/test-data/file.json")) { + assertThat(is.readAllBytes()).isNotEmpty(); + } + } } diff --git a/lang/src/test/resources/test-data/file.json b/lang/src/test/resources/test-data/file.json new file mode 100644 index 0000000000..7ae9aaa5f0 --- /dev/null +++ b/lang/src/test/resources/test-data/file.json @@ -0,0 +1 @@ +my file From 2409dca0f68875f2c40b6a162263b5a3b778a603 Mon Sep 17 00:00:00 2001 From: lprimak Date: Thu, 21 May 2026 04:26:20 -0500 Subject: [PATCH 2/3] satisfy precommit --- lang/src/test/resources/test-data/file.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lang/src/test/resources/test-data/file.json b/lang/src/test/resources/test-data/file.json index 7ae9aaa5f0..16d8c22fa0 100644 --- a/lang/src/test/resources/test-data/file.json +++ b/lang/src/test/resources/test-data/file.json @@ -1 +1,4 @@ -my file +{ + "id": 1, + "name": "example" +} From 332e93ab9f46f26bba5e21060e3e86a828cebe4c Mon Sep 17 00:00:00 2001 From: lprimak Date: Sat, 23 May 2026 22:48:48 -0500 Subject: [PATCH 3/3] core review fix --- lang/src/main/java/org/apache/shiro/lang/io/ResourceUtils.java | 2 +- .../test/java/org/apache/shiro/lang/util/ClassUtilsTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lang/src/main/java/org/apache/shiro/lang/io/ResourceUtils.java b/lang/src/main/java/org/apache/shiro/lang/io/ResourceUtils.java index 08f95688d4..3a1a224cb4 100644 --- a/lang/src/main/java/org/apache/shiro/lang/io/ResourceUtils.java +++ b/lang/src/main/java/org/apache/shiro/lang/io/ResourceUtils.java @@ -135,7 +135,7 @@ public static InputStream getInputStreamForPath(String resourcePath) throws IOEx * ({@link #CLASSPATH_PREFIX CLASSPATH_PREFIX}, * {@link #URL_PREFIX URL_PREFIX}, or {@link #FILE_PREFIX FILE_PREFIX}). If the path is not prefixed by one * of these schemes, the path is assumed to be a file-based path that can be loaded with a - * call to {@link URI#create(String)}. + * call to {@link Paths#get(String, String...)}. * * @param resourcePath the String path representing the resource to obtain. * @return the URL for the specified resource. diff --git a/lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java b/lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java index 2ab783e998..d190f6dd7f 100644 --- a/lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java +++ b/lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java @@ -87,7 +87,7 @@ void testGetClass() { } @Test - void inputStream() throws IOException { + void inputStreamFileLoading() throws IOException { try (InputStream is = getInputStreamForPath("classpath:org/apache/shiro/lang/util/ClassUtilsTest.class")) { assertThat(is.readAllBytes()).isNotEmpty(); }