I'm trying to refactor some legacy code using java.io.File
to use java.nio.file.Path
instead.
I'm bitten by the fact that Path has better support for absolute filepaths, because a lot of the values I receive have a leading slash (/
) while they are supposed to represent relative paths. String concatenation is easier that way but I'm trying to move away from String
/File
to represent filepaths.
The old behaviour was that new File(parent, child)
returned a new File
representing
/
.The new behaviour was that parent.resolve(child)
returned a new Path
representing either
/
)I think the new way can allow for cleaner code, but when refactoring a legacy application it can introduce subtle bugs.
What is the best/cleanest way to get back the old (File
) behaviour while using Path
?
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
class Main {
public static void main(String[] args) {
file();
path();
}
public static void file(){
File root = new File("/root");
File relative = new File(root, "relative");
File absolute = new File(root, "/absolute");
System.out.println("File:");
System.out.println(relative.getAbsolutePath()); // prints "/root/relative"
System.out.println(absolute.getAbsolutePath()); // prints "/root/absolute"
System.out.println();
}
public static void path(){
Path root = Paths.get("/root");
Path relative = root.resolve("relative");
Path absolute = root.resolve("/absolute");
System.out.println("Path:");
System.out.println(relative.toAbsolutePath()); // prints "/root/relative"
System.out.println(absolute.toAbsolutePath()); // prints "/absolute" but should print "/root/absolute"
System.out.println();
}
}
Basically what I want is a method that takes a parent Path, and a child String that returns me the parent+child Path regardless of whether the child had a leading /
.
Something like this, but without the String manipulations that depend on me knowing that the configuration will use /
(and not \
):
private static Path resolveSafely(Path parent, String child) {
child = child.startsWith("/")
? child.substring(1)
: child;
parent.resolve(child);
}
The best way I could find is this:
Path root = Paths.get("/root");
Path relative = root.resolve("relative");
Path absolute = Paths.get(root.toString(), "/absolute");
System.out.println("Path:");
System.out.println(relative.toAbsolutePath()); // prints "/root/relative"
System.out.println(absolute.toAbsolutePath()); // prints "/root/absolute"
System.out.println();
Hopefully that's all you need.
Edit: Since Java 11, Path.of()
is available and is the recommended way of obtaining Path objects instead of Paths.get()
. Check javadoc which also states that Paths
class may be deprecated in a future release.