ReadOnlyBooleanWrapper:与Bindings.or一起使用时的行为不正确

时间:2015-09-29 14:46:56

标签: java javafx property-binding

使用ReadOnlyBooleanWrapper绑定两个Binding.or对象时遇到了一种非常奇怪的行为。也就是说,当我对第一个参数执行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的文档:

  

此类提供了一个方便的类来定义只读属性。它会创建两个同步的属性。一个属性是只读的,可以传递给外部用户。另一个属性是可读写的,只能在内部使用。

1 个答案:

答案 0 :(得分:2)

这是一个错误(imo)。

正在发生的事情是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来计算绑定。我建议你报告这个bug。