Browse Source

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
pull/29139/head
Sam Brannen 4 years ago
parent
commit
138f9c64be
  1. 4
      spring-core/src/main/java/org/springframework/aot/hint/ResourceHints.java
  2. 45
      spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java
  3. 8
      spring-core/src/test/java/org/springframework/core/io/ClassPathResourceTests.java

4
spring-core/src/main/java/org/springframework/aot/hint/ResourceHints.java

@ -118,11 +118,11 @@ public class ResourceHints { @@ -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);

45
spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java

@ -45,6 +45,10 @@ import org.springframework.util.StringUtils; @@ -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 { @@ -119,44 +123,13 @@ public class ClassPathResource extends AbstractFileResolvingResource {
/**
* Return the path for this resource.
* <p>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
* <em>absolute path</em> supplied to the constructor, <strong>without</strong>
* a leading slash.
* <p>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
* <em>absolute path</em> supplied to the constructor, <strong>with</strong>
* a leading slash.
* <p>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
* <em>relative path</em> supplied to the constructor.
* <p>The path returned by this method cannot be reliably used with
* {@link ClassLoader#getResource(String)}.
* <p>If you consistently need the <em>absolute path</em>, use
* {@link #getAbsolutePath()} instead.
* @see #getAbsolutePath()
* Return the <em>absolute path</em> for this resource, as a
* {@linkplain StringUtils#cleanPath(String) cleaned} resource path within
* the class path.
* <p>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 <em>absolute path</em> for this resource, as a resource path
* within the class path without a leading slash.
* <p>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;
}

8
spring-core/src/test/java/org/springframework/core/io/ClassPathResourceTests.java

@ -103,9 +103,11 @@ class ClassPathResourceTests { @@ -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

Loading…
Cancel
Save