java - パスの.relativize()ドキュメントのバグか、ここで露骨に何か間違ったことをしていますか?

原文 java filesystems java.nio.file

さて、ここで楽しいものがあります。ここでの「要素」はPathElementsのインスタンスであり、これらの.resolve()および.relativize()fully testedおよびknown to workであることに注意してください...関連するメソッド実装へのリンクPath.resolve()Path.relativize()

失敗したテストメソッドの抜粋:

/*
 * This test this part of the Path's .relativize() method:
 *
 * <p> For any two {@link #normalize normalized} paths <i>p</i> and
 * <i>q</i>, where <i>q</i> does not have a root component,
 * <blockquote>
 * <i>p</i><tt>.relativize(</tt><i>p</i><tt>.resolve(</tt><i>q</i><tt>))
 * .equals(</tt><i>q</i><tt>)</tt>
 * </blockquote>
 *
 * Unfortunately, that turns out NOT TO BE TRUE! Whether p is absolute or
 * relative, it is indeed the case that the path elements (root, names) are
 * the same but the filesystem DIFFERS.
 *
 * An as Path's .equals() requires that the two filesystems be equal in
 * order for two Paths to be equals, this contract can not be obeyed; or I
 * am doing something VERY wrong.
 */
@Test(enabled = false)
public void relativizeResolveRoundRobinWorks()
{
    /*
     * In order to set up the environment we define a mock
     * FileSystemProvider which both our mock filesystems will return when
     * .provider() is called.
     *
     * We also suppose that the same PathElementsFactory is used; while this
     * code is not written yet, there should be only one such factory per
     * FileSystemProvider anyway (which is fed into all generated FileSystem
     * instances -- at least that's the plan).
     *
     * Note that this test method assumes that .equals() and .hashCode() are
     * not implemented on GenericPath. As such we check that the FileSystem
     * is the same (this is required by Path's equals()) and that the path
     * elements are the same (this is this package's requirements).
     */
    final FileSystemProvider fsProvider = mock(FileSystemProvider.class);
    final PathElementsFactory elementsFactory
        = new UnixPathElementsFactory();
    final FileSystem fsForP = mock(FileSystem.class);
    final FileSystem fsForQ = mock(FileSystem.class);

    when(fsForP.provider()).thenReturn(fsProvider);
    when(fsForQ.provider()).thenReturn(fsProvider);

    /*
     * The path to be operated. As the contract says, it has no root
     * component.
     */
    final GenericPath q = new GenericPath(fsForQ, elementsFactory,
        new PathElements(null, new String[] { "q1", "q2" }));

    /*
     * The path against which both resolution and relativization are
     * performed. We take two versions of it: a non absolute one and an
     * absolute one.
     *
     * Note that since we use a UnixPathElementsFactory, we equate an
     * absolute path (or not) to a path which has a root component (or not).
     */
    GenericPath p;
    // "rr" as in "resolved, relativized"
    GenericPath rr;

    final CustomSoftAssertions soft = CustomSoftAssertions.create();

    /*
     * Try with the absolute version first...
     */
    p = new GenericPath(fsForP, elementsFactory,
        new PathElements("/", new String[] { "p1", "p2" }));
    rr = (GenericPath) p.relativize(p.resolve(q));

    soft.assertThat(rr.getFileSystem())
        .as("rr and q filesystems should be the same (p absolute)")
        .isSameAs(q.getFileSystem());
    soft.assertThat(rr.elements).hasSameContentsAs(q.elements);

    /*
     * Now with the non absolute version
     */
    p = new GenericPath(fsForP, elementsFactory,
        new PathElements(null, new String[] { "p1", "p2" }));
    rr = (GenericPath) p.relativize(p.resolve(q));

    soft.assertThat(rr.getFileSystem())
        .as("rr and q filesystems should be the same (p not absolute)")
        .isSameAs(q.getFileSystem());
    soft.assertThat(rr.elements).hasSameContentsAs(q.elements);

    soft.assertAll();
}


このテストは失敗します:

org.assertj.core.api.SoftAssertionError: 
The following 2 assertions failed:
1) [rr and q filesystems should be the same (p absolute)] 
Expecting:
 <Mock for FileSystem, hashCode: 1125642929>
and actual:
 <Mock for FileSystem, hashCode: 1497261280>
to refer to the same object
2) [rr and q filesystems should be the same (p not absolute)] 
Expecting:
 <Mock for FileSystem, hashCode: 1125642929>
and actual:
 <Mock for FileSystem, hashCode: 1497261280>
to refer to the same object


そして明らかにそうです!


r = p.resolve(q)は、qではなく、pと同じファイルシステムを共有するパスを提供します。
したがって、p.relativize(r)は、pと同じファイルシステムのパスも提供します。
ただし、パスコントラクトでは、2つのパスを等しくするために、同じファイルシステムを共有する必要があります。


そして、これはこのシナリオでは常に誤りです。

それで、これはドキュメンテーションの露骨なバグですか、それとも私は見落としているのですか?
答え
A:ドキュメントでは、他のファイルシステムからのパスについては触れられていません。

resolveとrelativizeのドキュメントはここでは完全に明確ではありません。
ただし、引数パスが別のファイルシステムからのものである場合、relativizeはProviderMismatchExceptionをスローする必要があります。
あなたのテストはもっと早く投げるべきです。

パスの制約は、ファイルシステムによってまったく異なる場合があります。相対化のケースを考えてみましょう。あるファイルシステムから別の切り離されたファイルシステムまで歩くことができるパスはどのように見えるべきですか?

注:私はいくつかのFileSystem実装をテストし、その場合はすべてスローしました。
関連記事

java - クラス階層とセットアップ

java - Usage TrackerのJavaプロパティファイルでユーザー名を解決する

java - ボタン付きのビューページャーでフラグメント間をスワイプできません

java - 同じアクティビティ内のAdMobとWebViewが機能しない(Androidアプリ)

java - Android Gstreamer SDKでANativeWindow_lockがエラー-22を返す

java - Lucene Library 4.1.0でプラス記号をエスケープする方法

java - 特定のメソッドからのメソッドへの呼び出しの検出または防止

java - Randomインスタンスをグローバルに宣言する必要があります。もっと良い方法はありますか?

java - ArrayList全体にクラスメソッドを適用する

java - Java 2次元配列と平均