From 138f9c64beecd46a294af3db632a2156c98ce56c Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 12 Sep 2022 16:35:56 +0200 Subject: [PATCH] Consistently return absolute path from ClassPathResource#getPath Prior to this commit, the Javadoc for the getPath() method in ClassPathResource stated the following. > Return the path for this resource (as resource path within the class path). That implied the returned path was an "absolute path" within the class path; however, that was not always true. If the resource was created using ClassPathResource(String) or ClassPathResource(String, ClassLoader), the returned path was a cleaned version of the ABSOLUTE PATH supplied to the constructor, WITHOUT a leading slash. If the resource was created using ClassPathResource(String, Class) with an absolute path, the returned path was a cleaned version of the ABSOLUTE PATH supplied to the constructor, WITH a leading slash. If the resource was created using ClassPathResource(String, Class) with a relative path, the returned path was a cleaned version of the RELATIVE PATH supplied to the constructor. In addition, ClassPathResource does not provide public access the Class passed to the ClassPathResource(String, Class) constructor. Consequently, the path returned by getPath() could not be reliably used with ClassLoader.getResource(String) or with the recently introduced registerResource(Resource) method in ResourceHints. This commit addresses this issue by ensuring that getPath() consistently returns the absolute path within the class path without a leading slash. See gh-29083 Reverts gh-29094 Closes gh-29099 --- .../aot/hint/ResourceHints.java | 4 +- .../core/io/ClassPathResource.java | 45 ++++--------------- .../core/io/ClassPathResourceTests.java | 8 ++-- 3 files changed, 16 insertions(+), 41 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/aot/hint/ResourceHints.java b/spring-core/src/main/java/org/springframework/aot/hint/ResourceHints.java index e17bd9934a2..12c5cee747a 100644 --- a/spring-core/src/main/java/org/springframework/aot/hint/ResourceHints.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/ResourceHints.java @@ -118,11 +118,11 @@ public class ResourceHints { * @throws IllegalArgumentException if the supplied resource is not a * {@link ClassPathResource} or does not {@linkplain Resource#exists() exist} * @see #registerPattern(String) - * @see ClassPathResource#getAbsolutePath() + * @see ClassPathResource#getPath() */ public void registerResource(Resource resource) { if (resource instanceof ClassPathResource classPathResource && classPathResource.exists()) { - registerPattern(classPathResource.getAbsolutePath()); + registerPattern(classPathResource.getPath()); } else { throw new IllegalArgumentException("Resource must be a ClassPathResource that exists: " + resource); diff --git a/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java b/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java index 4b96efc7d74..5015b644221 100644 --- a/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java @@ -45,6 +45,10 @@ import org.springframework.util.StringUtils; */ public class ClassPathResource extends AbstractFileResolvingResource { + /** + * Internal representation of the original path supplied by the user, + * used for creating relative paths and resolving URLs and InputStreams. + */ private final String path; private final String absolutePath; @@ -119,44 +123,13 @@ public class ClassPathResource extends AbstractFileResolvingResource { /** - * Return the path for this resource. - *

If this resource was created using - * {@link ClassPathResource#ClassPathResource(String) ClassPathResource(String)} - * or {@link ClassPathResource#ClassPathResource(String, ClassLoader) - * ClassPathResource(String, ClassLoader)}, the returned path is a - * {@linkplain StringUtils#cleanPath(String) cleaned} version of the - * absolute path supplied to the constructor, without - * a leading slash. - *

If this resource was created using - * {@link ClassPathResource#ClassPathResource(String, Class) - * ClassPathResource(String, Class)} with an absolute path, the returned path - * is a {@linkplain StringUtils#cleanPath(String) cleaned} version of the - * absolute path supplied to the constructor, with - * a leading slash. - *

If this resource was created using - * {@link ClassPathResource#ClassPathResource(String, Class) - * ClassPathResource(String, Class)} with a relative path, the returned path - * is a {@linkplain StringUtils#cleanPath(String) cleaned} version of the - * relative path supplied to the constructor. - *

The path returned by this method cannot be reliably used with - * {@link ClassLoader#getResource(String)}. - *

If you consistently need the absolute path, use - * {@link #getAbsolutePath()} instead. - * @see #getAbsolutePath() + * Return the absolute path for this resource, as a + * {@linkplain StringUtils#cleanPath(String) cleaned} resource path within + * the class path. + *

The path returned by this method does not have a leading slash and is + * suitable for use with {@link ClassLoader#getResource(String)}. */ public final String getPath() { - return this.path; - } - - /** - * Return the absolute path for this resource, as a resource path - * within the class path without a leading slash. - *

The path returned by this method is suitable for use with - * {@link ClassLoader#getResource(String)}. - * @since 6.0 - * @see #getPath() - */ - public final String getAbsolutePath() { return this.absolutePath; } 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 9720f081d8d..f496c35ec82 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 @@ -103,9 +103,11 @@ class ClassPathResourceTests { } @Test - void preserveLeadingSlashForClassRelativeAccess() { - assertThat(new ClassPathResource("/test.html", getClass()).getPath()).isEqualTo("/test.html"); - assertThat(((ClassPathResource) new ClassPathResource("", getClass()).createRelative("/test.html")).getPath()).isEqualTo("/test.html"); + void convertToAbsolutePathForClassRelativeAccess() { + assertThat(new ClassPathResource("/test.html", getClass()).getPath()).isEqualTo("test.html"); + assertThat(new ClassPathResource("", getClass()).getPath()).isEqualTo(PACKAGE_PATH + "/"); + assertThat(((ClassPathResource) new ClassPathResource("", getClass()).createRelative("/test.html")).getPath()).isEqualTo("test.html"); + assertThat(((ClassPathResource) new ClassPathResource("", getClass()).createRelative("test.html")).getPath()).isEqualTo(PACKAGE_PATH + "/test.html"); } @Test