Issue
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);
- java-8 (1.8.0_66 to be exact) prints
../../../../file.txt
. JavaDoc. - java-11 (11.0.4 to be exact) prints
../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
- the way to navigate from
/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?
Solution
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.
- java-8
sun.nio.fs.WindowsPath
source code at GitHub - java-11
sun.nio.fs.WindowsPath
source code at GitHub
The 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:
- Java 8 and below:
/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java
- Java 9 and above:
/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());
Answered By - Nikolas Charalambidis
Answer Checked By - Marilyn (JavaFixing Volunteer)