1

ReadOnlyBooleanWrapperを使用して 2 つのオブジェクトをバインドすると、非常に奇妙な動作に遭遇しましたBinding.orb1.set(true)つまり、最初の引数で行うと、結果は正しくありません (まだ false) 。

これは簡単な単体テストです (失敗します):

@Test
public void testReadOnlyBooleanWrapper() {
    // Fails!!!
    testOr(new ReadOnlyBooleanWrapper(false), new ReadOnlyBooleanWrapper(false));
}

public void testOr(BooleanProperty b1, BooleanProperty b2) {
    BooleanExpression or = b1.or(b2);

    assertEquals(or.get(), b1.get() || b2.get());
    b1.set(true);
    assertEquals(or.get(), b1.get() || b2.get());
    b1.set(false);
    assertEquals(or.get(), b1.get() || b2.get());
}

同じテストがSimpleBooleanProperties正常に機能することに注意してください。

@Test
public void testSimpleBooleanProperty() {
    // Passes
    testOr(new SimpleBooleanProperty(false), new SimpleBooleanProperty(false));
}

実装にそのようなバグがあるとは想像できないので、私はおそらくここでいくつかの点を見逃しており、プロパティを誤用しています! :)

それを説明する方法についてのアイデアをありがとう!

アップデート:

あなたの答えとコメントは私を正しい軌道に乗せました:)私はまだ解決策を持っていませんが、ラッパー自体ではなく(公開されていると思われる)にバインドすると、テストに合格することorに気付きましたReadOnlyProperties:

@Test
public void testOrReadOnly() {
    ReadOnlyBooleanWrapper b1 = new ReadOnlyBooleanWrapper(false);
    ReadOnlyBooleanWrapper b2 = new ReadOnlyBooleanWrapper(false);

    BooleanExpression or = b1.getReadOnlyProperty().or(b2.getReadOnlyProperty());

    System.out.println("Condition " + or.get());
    assertEquals(or.get(), b1.get() || b2.get());
    b1.set(true);
    System.out.println("Condition " + or.get());
    assertEquals(or.get(), b1.get() || b2.get());
    b1.set(false);
    System.out.println("Condition " + or.get());
    assertEquals(or.get(), b1.get() || b2.get());
}

これは、内部の読み取りおよび書き込み可能なプロパティと読み取り専用のプロパティの間の同期が何らかの形で壊れていると思います (?)

についてのドキュメントからReadOnlyBooleanWrapper

このクラスは、読み取り専用プロパティを定義するための便利なクラスを提供します。同期される 2 つのプロパティを作成します。1 つのプロパティは読み取り専用で、外部ユーザーに渡すことができます。もう 1 つのプロパティは読み取りと書き込みが可能で、内部でのみ使用する必要があります。

4

1 に答える 1

2

これはバグです (imo)。

何が起こっているかというと、orバインディングの実装が「or」のショートサーキットを実装しているということです (これはBindings.javaにあります)。

    @Override
    public void invalidated(Observable observable) {
        final BooleanOrBinding binding = ref.get();
        if (binding == null) {
            observable.removeListener(this);
        } else {
            // short circuit invalidation. This BooleanBinding becomes
            // only invalid if the first operator changes or the
            // first parameter is false.
            if ((binding.op1.equals(observable) || (binding.isValid() && !binding.op1.get()))) {
                binding.invalidate();
            }
        }
    }

orこれを実装するリスナーは、 :の各オペランドに追加されますがReadOnlyBooleanWrapper、リスナーをそのReadOnlyBooleanProperty( ReadOnlyBooleanWrapper.javaから)に委譲します。

@Override
public void addListener(InvalidationListener listener) {
    getReadOnlyProperty().addListener(listener);
}

したがって、ショートサーキットの実装では、binding.op1.equals(observable)ですfalse(1 つはReadOnlyBooleanWrapperであり、もう 1 つはその であるためReadOnlyBooleanProperty)。したがって、ここでのロジックは (誤って) 2 番目の演算子が変更されたと想定しています。最初の演算子の値trueは であるため、実装の結論として、 の評価はor変更できず、無効化は発生しません。したがって、あなたorは再評価されません。

あなたが発見したように、回避策はReadOnlyBooleanProperty、バインディングの計算にラップを使用することです。このバグを報告することをお勧めします。

于 2015-09-29T15:37:17.600 に答える