RFR: 8298318: (fs) APIs for handling filename extensions [v2]

Anthony Vanelverdinghe duke at openjdk.org
Thu Nov 30 10:33:12 UTC 2023


On Mon, 20 Nov 2023 23:30:45 GMT, Brian Burkhalter <bpb at openjdk.org> wrote:

>> Add to `java.nio.file.Path` a method `getExtension` to retrieve the `Path`'s extension, and companion methods `removeExtension` and `addExtension`.
>
> Brian Burkhalter has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains three additional commits since the last revision:
> 
>  - 8298318: Correct type in path.getExtension spec
>  - Merge
>  - 8298318: (fs) APIs for handling filename extensions

The more I think about it, the more I'm convinced that the concept of a filename is sufficiently complex to warrant its own type. Moreover, I believe extension-specific APIs would be out of place in `Path`, as they apply to a single name, whereas `Path` is all about a sequence of names. While an additional type would increase the API surface, the existing `Path::getFileName` can be repurposed (if I'm correct that the proposed change would be a compatible one).

So I'd like to propose:

* introducing an interface `Filename` which extends `Path` and `CharSequence`
* changing `Path::getFileName` to return an instance of `Filename`

where `Filename` would look something like below and would allow code such as:


var foo = Path.of(".foo.tar.gz").getFileName();
if(foo.extension().equals(".gz") && foo.base().extension().equals(".tar")) {
    var name = foo.base().base();
    assert "foo".contentEquals(name);
}



/**
 * Represents a filename.
 * 
 * Invariant (pseudocode): hidden() + base() + extension() = toString()
 */
interface Filename extends Path, CharSequence {

    /**
     * An enum that allows overriding how the filename must be interpreted.
     */
    enum DotOption {
        HIDDEN_MARKER_AS_LEADING_DOT,
        NO_HIDDEN_MARKER
    }

    /**
     * {@return the hidden marker}
     * 
     * If this instance represents a Filename where a leading dot serves as a "hidden" marker
     * or DotOption.HIDDEN_MARKER_AS_LEADING_DOT is specified,
     * returns `Optional.of(...)`
     * If this instance represents a Filename where a leading dot has no special meaning
     * or DotOption.NO_HIDDEN_MARKER is specified,
     * returns `Optional.empty()`
     */
    Optional<Boolean> hidden(DotOption... options);

    /**
     * {@return the filename without the hidden marker and the file extension}
     */
    Filename base();

    /**
     * {@return the file extension including the dot}
     * 
     * The filenames `.` and `..` don't have an extension.
     * 
     * For filenames with a single, leading dot:
     * If this instance represents a Filename where a leading dot serves as a "hidden" marker
     * or DotOption.HIDDEN_MARKER_AS_LEADING_DOT is specified,
     * returns the empty String
     * If this instance represents a Filename where a leading dot has no special meaning
     * or DotOption.NO_HIDDEN_MARKER is specified,
     * returns the whole filename
     * 
     * For any other filenames, the extension is the substring starting at the last dot.
     */
    String extension(DotOption... options);

    // TODO: consider additional methods such as withExtension, withoutExtension, ...
}

-------------

PR Comment: https://git.openjdk.org/jdk/pull/16226#issuecomment-1833489866


More information about the nio-dev mailing list