8030090: (fs) Add default methods to Path for derived methods

Use method bodies from sun.nio.fs.AbstractPath as default method implementations in Path.

Reviewed-by: alanb
This commit is contained in:
Brian Burkhalter 2014-12-23 10:09:52 -08:00
parent befd7d1c25
commit 0062f27c96
4 changed files with 108 additions and 120 deletions
jdk/src/java.base
share/classes
java/nio/file
sun/nio/fs
unix/classes/sun/nio/fs
windows/classes/sun/nio/fs

@ -29,6 +29,7 @@ import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* An object that may be used to locate a file in a file system. It will
@ -246,6 +247,12 @@ public interface Path
* "{@code foo/bar}" starts with "{@code foo}" and "{@code foo/bar}". It
* does not start with "{@code f}" or "{@code fo}".
*
* @implSpec
* The default implementation is equivalent for this path to:
* <pre>{@code
* startsWith(getFileSystem().getPath(other));
* }</pre>
*
* @param other
* the given path string
*
@ -255,7 +262,9 @@ public interface Path
* @throws InvalidPathException
* If the path string cannot be converted to a Path.
*/
boolean startsWith(String other);
default boolean startsWith(String other) {
return startsWith(getFileSystem().getPath(other));
}
/**
* Tests if this path ends with the given path.
@ -294,6 +303,12 @@ public interface Path
* Path}"{@code foo/bar}" with the {@code String} "{@code bar/}" returns
* {@code true}.
*
* @implSpec
* The default implementation is equivalent for this path to:
* <pre>{@code
* endsWith(getFileSystem().getPath(other));
* }</pre>
*
* @param other
* the given path string
*
@ -303,7 +318,9 @@ public interface Path
* @throws InvalidPathException
* If the path string cannot be converted to a Path.
*/
boolean endsWith(String other);
default boolean endsWith(String other) {
return endsWith(getFileSystem().getPath(other));
}
/**
* Returns a path that is this path with redundant name elements eliminated.
@ -365,6 +382,12 @@ public interface Path
* invoking this method with the path string "{@code gus}" will result in
* the {@code Path} "{@code foo/bar/gus}".
*
* @implSpec
* The default implementation is equivalent for this path to:
* <pre>{@code
* resolve(getFileSystem().getPath(other));
* }</pre>
*
* @param other
* the path string to resolve against this path
*
@ -375,7 +398,9 @@ public interface Path
*
* @see FileSystem#getPath
*/
Path resolve(String other);
default Path resolve(String other) {
return resolve(getFileSystem().getPath(other));
}
/**
* Resolves the given path against this path's {@link #getParent parent}
@ -389,6 +414,14 @@ public interface Path
* returns this path's parent, or where this path doesn't have a parent, the
* empty path.
*
* @implSpec
* The default implementation is equivalent for this path to:
* <pre>{@code
* (getParent() == null) ? other : getParent().resolve(other);
* }</pre>
* unless {@code other == null}, in which case a
* {@code NullPointerException} is thrown.
*
* @param other
* the path to resolve against this path's parent
*
@ -396,13 +429,24 @@ public interface Path
*
* @see #resolve(Path)
*/
Path resolveSibling(Path other);
default Path resolveSibling(Path other) {
if (other == null)
throw new NullPointerException();
Path parent = getParent();
return (parent == null) ? other : parent.resolve(other);
}
/**
* Converts a given path string to a {@code Path} and resolves it against
* this path's {@link #getParent parent} path in exactly the manner
* specified by the {@link #resolveSibling(Path) resolveSibling} method.
*
* @implSpec
* The default implementation is equivalent for this path to:
* <pre>{@code
* resolveSibling(getFileSystem().getPath(other));
* }</pre>
*
* @param other
* the path string to resolve against this path's parent
*
@ -413,7 +457,9 @@ public interface Path
*
* @see FileSystem#getPath
*/
Path resolveSibling(String other);
default Path resolveSibling(String other) {
return resolveSibling(getFileSystem().getPath(other));
}
/**
* Constructs a relative path between this path and a given path.
@ -590,12 +636,28 @@ public interface Path
* File} object returned by this method is {@link #equals equal} to the
* original {@code File}.
*
* @implSpec
* The default implementation is equivalent for this path to:
* <pre>{@code
* new File(toString());
* }</pre>
* if the {@code FileSystem} which created this {@code Path} is the default
* file system; otherwise an {@code UnsupportedOperationException} is
* thrown.
*
* @return a {@code File} object representing this path
*
* @throws UnsupportedOperationException
* if this {@code Path} is not associated with the default provider
*/
File toFile();
default File toFile() {
if (getFileSystem() == FileSystems.getDefault()) {
return new File(toString());
} else {
throw new UnsupportedOperationException("Path not associated with "
+ "default file system.");
}
}
// -- watchable --
@ -681,6 +743,13 @@ public interface Path
*
* WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
* </pre>
*
* @implSpec
* The default implementation is equivalent for this path to:
* <pre>{@code
* register(watcher, events, new WatchEvent.Modifier[0]);
* }</pre>
*
* @param watcher
* The watch service to which this object is to be registered
* @param events
@ -706,9 +775,10 @@ public interface Path
* method is invoked to check read access to the file.
*/
@Override
WatchKey register(WatchService watcher,
WatchEvent.Kind<?>... events)
throws IOException;
default WatchKey register(WatchService watcher,
WatchEvent.Kind<?>... events) throws IOException {
return register(watcher, events, new WatchEvent.Modifier[0]);
}
// -- Iterable --
@ -721,10 +791,36 @@ public interface Path
* is the name of the file or directory denoted by this path. The {@link
* #getRoot root} component, if present, is not returned by the iterator.
*
* @implSpec
* The default implementation returns an {@code Iterator<Path>} which, for
* this path, traverses the {@code Path}s returned by
* {@code getName(index)}, where {@code index} ranges from zero to
* {@code getNameCount() - 1}, inclusive.
*
* @return an iterator over the name elements of this path.
*/
@Override
Iterator<Path> iterator();
default Iterator<Path> iterator() {
return new Iterator<Path>() {
private int i = 0;
@Override
public boolean hasNext() {
return (i < getNameCount());
}
@Override
public Path next() {
if (i < getNameCount()) {
Path result = getName(i);
i++;
return result;
} else {
throw new NoSuchElementException();
}
}
};
}
// -- compareTo/equals/hashCode --

@ -1,106 +0,0 @@
/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.fs;
import java.nio.file.*;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Base implementation class of {@code Path}.
*/
abstract class AbstractPath implements Path {
protected AbstractPath() { }
@Override
public final boolean startsWith(String other) {
return startsWith(getFileSystem().getPath(other));
}
@Override
public final boolean endsWith(String other) {
return endsWith(getFileSystem().getPath(other));
}
@Override
public final Path resolve(String other) {
return resolve(getFileSystem().getPath(other));
}
@Override
public final Path resolveSibling(Path other) {
if (other == null)
throw new NullPointerException();
Path parent = getParent();
return (parent == null) ? other : parent.resolve(other);
}
@Override
public final Path resolveSibling(String other) {
return resolveSibling(getFileSystem().getPath(other));
}
@Override
public final Iterator<Path> iterator() {
return new Iterator<Path>() {
private int i = 0;
@Override
public boolean hasNext() {
return (i < getNameCount());
}
@Override
public Path next() {
if (i < getNameCount()) {
Path result = getName(i);
i++;
return result;
} else {
throw new NoSuchElementException();
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public final File toFile() {
return new File(toString());
}
@Override
public final WatchKey register(WatchService watcher,
WatchEvent.Kind<?>... events)
throws IOException
{
return register(watcher, events, new WatchEvent.Modifier[0]);
}
}

@ -40,9 +40,7 @@ import static sun.nio.fs.UnixConstants.*;
* Solaris/Linux implementation of java.nio.file.Path
*/
class UnixPath
extends AbstractPath
{
class UnixPath implements Path {
private static ThreadLocal<SoftReference<CharsetEncoder>> encoder =
new ThreadLocal<SoftReference<CharsetEncoder>>();

@ -41,7 +41,7 @@ import static sun.nio.fs.WindowsConstants.*;
* Windows implementation of Path
*/
class WindowsPath extends AbstractPath {
class WindowsPath implements Path {
// The maximum path that does not require long path prefix. On Windows
// the maximum path is 260 minus 1 (NUL) but for directories it is 260