Why does the method relativize
behave differently on java-8 and java-11?
Path path1 = Paths.get("/a/./b/../image.png");
Path path2 = Paths.get("/a/file.txt");
Path path = path1.relativize(path2);
System.out.println(path);
../../../../file.txt
. JavaDoc.../file.txt
. JavaDoc.The JavaDoc description of both versions is equal. I feel the java-11 way looks like a correct behavior to me:
path1
: /a/./b/../image.png
normalizes to /a/b/../image.png
which normalizes to /a/image.png
path2
: /a/file.txt
/a/image.png
and /a/file.txt
is ../file.txt
Questions
How is the java-8 way supposed to be calculated? Doesn't it normalize the path? I don't understand how to get the result from head.
Why is there a difference between these two versions that is not documented at all?
Windows based source-code answer here.
From the observation of the source codes (let's take a look at sun.nio.fs.WindowsPath
, one of the implementations of Path
) in java-11 is has additional code including normalization compared to java-8.
sun.nio.fs.WindowsPath
source code at GitHubsun.nio.fs.WindowsPath
source code at GitHubThe key line of the latter implementation starts at the line 411, so basically, the latter implementation normalizes the paths before taking into calculation of the relative path:
WindowsPath base = this;
if (base.hasDotOrDotDot() || child.hasDotOrDotDot()) {
base = base.normalize();
child = child.normalize();
}
Digging further, the implementation changes between jdk8-b120
(source) and jdk-9+95
(source). Since the modular system was introduced, both the classes implementation and location differ:
/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java
/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsPath.java
How is the java-8 way supposed to be calculated? Doesn't it normalize the path? I don't understand how to get the result from head.
The most straightforward way to go is to normalize both paths first before relativizing them. But I have no idea whether it completely covers all the java.nio.file.Path
implementations and is safe to do so.
Path path = path1.normalize().relativize(path2.normalize());