All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.fge.filesystem.MorePaths Maven / Gradle / Ivy

package com.github.fge.filesystem;

import com.github.fge.filesystem.exceptions.UnresolvablePathException;

import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import java.nio.file.FileSystem;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.ProviderMismatchException;
import java.nio.file.spi.FileSystemProvider;
import java.util.Objects;

/**
 * {@link Path} utility methods
 *
 * 

Unless otherwise noted, all methods in this class do not accept null * arguments and will throw a {@link NullPointerException} if a null argument * is passed to them.

*/ @ParametersAreNonnullByDefault public final class MorePaths { private MorePaths() { throw new Error("nice try!"); } /** * Resolve a path against another path with a potentially different * {@link FileSystem} or {@link FileSystemProvider} * *

{@link Path#resolve(Path)} will refuse to operate if its argument is * issued from a different provider (with a {@link * ProviderMismatchException}); moreover, if the argument is issued from the * same provider but is on a different filesystem, the result of the * resolution may be on the argument's filesystem, not the caller's.

* *

This method will attempt to resolve the second path against the first * so that the result is always associated to the filesystem (and * therefore provider) of the first argument. For the resolution to operate, * the following conditions must be met for {@code path2}:

* *
    *
  • if it is not absolute, it must not have a root;
  • *
  • if it is absolute, it must have a root, and the string * representation of this root must match a string representation of one * possible root of the first path's filesystem.
  • *
* *

If the conditions above are not satisfied, this method throws an * {@link UnresolvablePathException} (unchecked).

* *

If both paths are issued from the same filesystem, this method will * delegate to {@code path1}'s {@code .resolve()}; if they are from * different filesystems but share the same provider, this method returns: *

* *
     *     path1.resolve(path1.getFileSystem().getPath(path2.toString()))
     * 
* *

This means that for instance it is possible to resolve a Unix path * against a Windows path, or the reverse, as long as the second path is * not absolute (the root paths of both filesystems are incompatible):

* *
    *
  • resolving {@code foo/bar/baz} against {@code c:} will return * {@code c:\foo\bar\baz};
  • *
  • resolving {@code baz\quux} against {@code /foo/bar} will return * {@code /foo/bar/baz/quux}.
  • *
* * @param path1 the first path * @param path2 the second path * @return the resolved path * @throws UnresolvablePathException see description * @throws InvalidPathException {@code path2} is from a different provider, * and one of its name elements is invalid according to {@code path1}'s * filesystem * * @see FileSystem#getPath(String, String...) * @see FileSystem#getRootDirectories() */ @SuppressWarnings("ObjectEquality") @Nonnull public static Path resolve(final Path path1, final Path path2) { final FileSystem fs1 = Objects.requireNonNull(path1).getFileSystem(); final FileSystem fs2 = Objects.requireNonNull(path2).getFileSystem(); if (fs1 == fs2) return path1.resolve(path2); if (fs1.provider() == fs2.provider()) return path1.resolve(fs1.getPath(path2.toString())); final boolean isAbsolute = path2.isAbsolute(); final Path root2 = path2.getRoot(); final String errmsg = isAbsolute ? "path to resolve is absolute but has no root" : "path to resolve is not absolute but has a root"; // Always tricky to read an xor... if (isAbsolute ^ root2 != null) throw new UnresolvablePathException(errmsg); Path ret; if (isAbsolute) { /* * Check if the root of path2 is compatible with path1 */ final String path2Root = root2.toString(); boolean foundRoot = false; for (final Path root1: fs1.getRootDirectories()) if (root1.toString().equals(path2Root)) foundRoot = true; if (!foundRoot) throw new UnresolvablePathException("root of path to resolve " + "is incompatible with source path"); ret = fs1.getPath(path2Root); } else { /* * Since the empty path is defined as having one empty name * component, which is rather awkward, we don't want to take the * risk of triggering bugs in FileSystem#getPath(); instead, check * that the string representation of path2 is empty, and if it is, * just return path1. */ if (path2.toString().isEmpty()) return path1; ret = path1; } for (final Path element: path2) ret = ret.resolve(element.toString()); return ret; } /** * Normalizes the given path * *

On Unix systems and at least up to Oracle JDK 7u51 and 8u15, * {@code Paths.get("").normalize()} will throw an {@link * ArrayIndexOutOfBoundsException}. See this bug * entry.

* *

This method works around the problem by testing that the path is * empty (its string representation is empty); if this is the case, it is * returned as is. Otherwise, normalization is performed normally.

* * @param path the path * @return the normalized path */ @Nonnull public static Path normalize(final Path path) { return Objects.requireNonNull(path).toString().isEmpty() ? path : path.normalize(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy