ReadOnlyBooleanWrapper:与 Bindings.or 一起使用时的错误行为

ReadOnlyBooleanWrapper: incorrect behaviour when used with Bindings.or

我在使用 Binding.or 绑定两个 ReadOnlyBooleanWrapper 对象时遇到了一个非常奇怪的行为。也就是说,当我对第一个参数执行 b1.set(true) 时,结果不正确(仍然是错误的)。

这是一个简单的单元测试(失败):

@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 的文档:

This class provides a convenient class to define read-only properties. It creates two properties that are synchronized. One property is read-only and can be passed to external users. The other property is read- and writable and should be used internally only.

这是一个错误 (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(因为一个是ReadOnlyBooleanWrapper,另一个是它的ReadOnlyBooleanProperty)。所以这里的逻辑是(错误地)假设第二个运算符已经改变。由于第一个运算符的值为 true,因此实施的结论是 or 的评估不可能发生变化,因此不会触发失效。因此,您的 or 不会被重新评估。

如您所见,解决方法是在计算绑定时使用包装的 ReadOnlyBooleanProperty。我建议你报告这个错误。