Why do I get ProviderMismatchException when I try to .relativize() a Path against another Path?
Asked Answered
M

1

14

[note: self answered question]

I have opened a FileSystem to a zip file using java.nio. I have gotten a Path from that filesystem:

final Path zipPath = zipfs.getPath("path/into/zip");

Now I have a directory on the local filesystem which I have obtained using:

final Path localDir = Paths.get("/local/dir")

I want to test whether /local/dir/path/into/zip exists, so I check its existence using:

Files.exists(localDir.resolve(zipPath))

but I get a ProviderMismatchException. Why? How do I fix this?

Mroz answered 24/3, 2014 at 14:15 Comment(0)
M
17

This behaviour is documented, albeit it is not very visible. You have to delve into the java.nio.file package description to see, right at the end, that:

Unless otherwise noted, invoking a method of any class or interface in this package created by one provider with a parameter that is an object created by another provider, will throw ProviderMismatchException.

The reasons for this behaviour may not be obvious, but consider for instance that two filesystems can define a different separator.

There is no method in the JDK which will help you there. If your filesystems use the same separator then you can work around this using:

path1.resolve(path2.toString())

Otherwise this utility method can help:

public static Path pathTransform(final FileSystem fs, final Path path)
{
    Path ret = fs.getPath(path.isAbsolute() ? fs.getSeparator() : "");
    for (final Path component: path)
        ret = ret.resolve(component.getFileName().toString());
    return ret;
}

Then the above can be written as:

final Path localPath = pathTransform(localDir.getFileSystem(), zipPath);
Files.exists(localDir.resolve(localPath));
Mroz answered 24/3, 2014 at 14:15 Comment(3)
I'm unable to get this working. Why is a component variable in the loop never used? And you forgot to set return type to Path and add brackets after isAbsolute() and getSeparator().Carner
So, ret is a Path of one provider and path of another. Then you still get ProviderMismatchException if you want to resolve them using component.getFileName() which returns Path, don't you?Carner
@Carner sigh I forgot .toString() after .getFileName()Mroz

© 2022 - 2024 — McMap. All rights reserved.