Add a means to convert a URI to a JimfsPath
eyalroth opened this issue · 7 comments
There is no obvious way to convert a URI into a JimfsPath
. Normally, one could use fs.provider().getPath(uri)
, but this is not implemented by JimfsFileSystemProvider
; instead, it throws an exception stating:
This method should not be called directly; use Paths.get(URI) instead.
Which is funny, since on #12 @cgdecker (main contributor to the project?)
strongly recommends not using
Paths.get
I would've used JimfsFileSystem.toPath(URI)
, but the entire class is set to the package-private access modifier (why the hell?).
Paths.get(URI)
is fine and is the correct way to get a Path
from a URI
... what I was referring to in that issue was Paths.get(String, String...)
, which can only get you a Path
from the default file system.
And JimfsFileSystem
is package-private because users should be able to do everything they need through the normal java.nio.file
APIs without using implementation details of Jimfs itself. It's a bit unfortunate that fs.provider().getPath(uri)
doesn't work; it's a side-effect of something else that had to be done.
Paths.get(URI)
is doing nothing but finding the file-system provider which matches the URI's scheme and resolving the URI using said provider's getPath(URI)
method. In case the scheme is file
, the method will use the default file system, much like its "sister" Paths.get(String)
; therefore, the same argument could be said for this method as well.
In other words, I'm a user of Jimfs and I would've liked to convert URIs with the file
scheme into a JimfsPath
, the same way I'm able to do with the default file system (which is what I take Jimfs to be an emulator for). fs.provider().getPath(URI)
is exactly the way to do this, and therefore I expect Jimfs to implement it. I would like to know what is the problem with implementing it; perhaps I could help.
For better or for worse, the design of the whole FileSystem
/ FileSystemProvider
API is such that each FileSystemProvider
must use its own URI scheme. Jimfs URIs start with jimfs:
. From that perspective, a file:
URI means a file on the default file system, period. Also, I'll note that fs.provider().getPath(URI)
is not intended as a way of getting a Path
for one FileSystem
from a URI
that belongs to a different FileSystemProvider
. FileSystemProvider
is an SPI type and generally not intended to be used by user code; FileSystem.provider()
mostly exists because it allows FileSystem
implementations to get at the provider when a Path
is passed to one of their methods.
So, if you have a file:
URI and want to get a Jimfs Path
? First I'd ask where the URI is coming from. If you could, rather than getting a file:
URI in the first place, call toUri()
on a Jimfs Path
to get the URI that you later want to turn into a Jimfs Path
.
Alternatively, you can probably do fs.getPath(uri.getPath())
and it'll just work like you want.
If it doesn't, it might be that constructing a new URI like new URI(anyJimfsPath.getScheme(), anyJimfsPath.getAuthority(), uri.getPath(), null, null)
will work, though I think that should basically be equivalent to the previous suggestion.
I see your point; the NIO API couples the default provider to the "file" scheme and it's quite hard to undo.
Yeah, fs.getPath(uri.getPath())
is exactly what I used instead (I didn't care for the authority here).
So I'm having an issue with creating a new URI from a path and I tried using new URI(anyJimfsPath.getScheme(), anyJimfsPath.getAuthority(), uri.getPath(), null, null)
but that didn't work. What I'm trying to do is create a new filesystem for a zip file using a path that was already created using Jimfs.
What I'm doing is this:
Path zipPath = pathFromJimfs;
URI zipURI = zipPath.toUri();
zipURI = new URI(zipURI.getScheme(), zipURI.getAuthority(), zipURI.getPath(), null, null);
Map<String, Object> env = new HashMap<>();
env.put("create", Boolean.toString(Files.notExists(outputZipAbsolutePath)));
env.put("encoding", "UTF-8");
FileSystem zipFileSystem = FileSystems.newFileSystem(zipURI, env);
I'm getting the following exception:
java.lang.IllegalArgumentException: uri (jimfs://11bee858-af79-4dee-aca1-5420ee1c8a00/pathtozip) may not have a path, query or fragment
I debugged the code and yes it does have a path that is not null.
Why isn't this working? I thought as long as the path object is jimfs then I can create a new filesystem using that path object and everything should work as is.
@o2themar You're getting that exception because you're calling FileSystems.newFileSystem(URI, Map)
with a URI with the scheme jimfs
. That tells Jimfs to create a new Jimfs file system, not a zip file system, and the URI for a Jimfs file system isn't allowed to have a path, query or fragment (because they don't make sense in that context).
The scheme for a zip file system is jar:<underlying file system scheme>
, so in the case of a file in a Jimfs file system, jar:jimfs
. So your code would probably work if you just pass "jar:" + zipURI.getScheme()
as the scheme for your new URI.
That said, you should be able to get a zip file system for a Jimfs path by just calling FileSystems.newFileSystem(Path, Map)
:
Path zipPath = pathFromJimfs;
Map<String, Object> env = new HashMap<>();
env.put("create", Boolean.toString(Files.notExists(outputZipAbsolutePath)));
env.put("encoding", "UTF-8");
FileSystem zipFileSystem = FileSystems.newFileSystem(zipPath, env);