Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Obtaining a URL from a jimfs Path #13

Closed
skuzzle opened this issue Sep 22, 2014 · 3 comments
Closed

Obtaining a URL from a jimfs Path #13

skuzzle opened this issue Sep 22, 2014 · 3 comments
Assignees
Labels
fixed type=enhancement Make an existing feature better
Milestone

Comments

@skuzzle
Copy link

skuzzle commented Sep 22, 2014

A framework I'm testing internally needs to obtain an URL from a passed in path. For testing, I'd like to use jimfs, but obtaining a URL from a jimfs path seems not to be possible. Calling path.toUri().toURL() throws a MalformedURLException with message: java.net.MalformedURLException: unknown protocol: jimfs. Is this something fixable or something to live with? Here is a simpe test case to reproduce:

import java.net.MalformedURLException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.Path;

import org.junit.Test;

import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;

public class JimFSTest {

    @Test
    public void testGetURL() throws MalformedURLException {
        final FileSystem fs = Jimfs.newFileSystem(Configuration.unix());
        final Path path = fs.getPath("foo", "bar");
        final URI uri = path.toUri();
        uri.toURL();
    }
}

Edit: I just found out that one can implement a URLStreamHandlerFactory to accomplish this. You might consider to ship a suitable implementation for jimfs.

@cgdecker
Copy link
Member

It looks like for this to work there has to be a URLStreamHandler that handles the jimfs scheme. It doesn't seem like there's an especially great way to make that happen automatically.

Manually, you can create an implementation and then do:

URL url = new URL(null, path.toUri().toString(), new JimfsURLStreamHandler());

It's also possible to use URL.setURLStreamHandlerFactory(URLStreamHandlerFactory) to statically set a factory to use for getting URLStreamHandlers for custom protocols. Setting that would allow uri.toURL() to work, but it doesn't seem like a good idea for Jimfs to set the URLStreamHandlerFactory automatically because it would conflict with anything else that may also try to set the factory (that method can only be called once).

The final piece of complexity is just how the URLStreamHandler should behave. If you just want reading files by URL to work, it should be enough to create a URLConnection that only overrides getInputStream().

@cgdecker cgdecker added the type=enhancement Make an existing feature better label Sep 22, 2014
@seanrohead
Copy link

You don't need to change the default stream handler factory for this to work. If you have a Handler class in a sub-package named 'jimfs', then you can simply set the "java.protocol.handler.pkgs" system property to the parent package. It would be very helpful if the Handler class and a UrlConnection class shipped with jimfs. Here are the classes I use:

public class Handler extends URLStreamHandler
{
    @Override
    protected URLConnection openConnection(URL url) throws IOException
    {
        return new JimfsUrlConnection(url);
    }
}

public class JimfsUrlConnection extends URLConnection
{
    private Path path;

    public JimfsUrlConnection(URL url)
    {
        super(url);
    }

    @Override
    public void connect() throws IOException
    {
        try
        {
            FileSystem fileSystem = FileSystems.getFileSystem(URI.create("jimfs://" + getURL().getAuthority()));
            path = fileSystem.getPath(getURL().getPath());
        }
        catch (FileSystemNotFoundException | InvalidPathException e)
        {
            throw new IOException(e);
        }
    }

    @Override
    public InputStream getInputStream() throws IOException
    {
        Preconditions.checkState(path != null);

        return Files.newInputStream(path);
    }
}

cgdecker added a commit that referenced this issue Feb 18, 2015
For URLs to work, Java has to be able to find a URLStreamHandler implementation for the URL protocol/scheme. There isn't any really ideal way to do this programatically, but what this CL does is add "com.google.common" to the "java.protocol.handler.pkgs" system property when JimfsFileSystemProvider is initialized. This means that when Java tries to create a URL with the "jimfs" protocol, it'll look for "jimfs.Handler" under "com.google.common", find it and use it. (Documentation of that behavior found here: http://docs.oracle.com/javase/8/docs/api/java/net/URL.html#URL-java.lang.String-java.lang.String-int-java.lang.String-)

Fixes Github issue #13.
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=86627713
@cgdecker cgdecker self-assigned this Feb 18, 2015
@cgdecker cgdecker added the fixed label Feb 18, 2015
@cgdecker
Copy link
Member

This is in now, using the java.protocol.handler.pkgs approach. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fixed type=enhancement Make an existing feature better
Projects
None yet
Development

No branches or pull requests

3 participants