【问题标题】:ReadOnlyBooleanWrapper: incorrect behaviour when used with Bindings.orReadOnlyBooleanWrapper:与 Bindings.or 一起使用时行为不正确
【发布时间】:2015-09-29 14:46:55
【问题描述】:

我在使用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));
}

我可能在这里遗漏了一些要点并滥用了属性,因为我无法想象实现中会出现这样的错误! :)

感谢任何想法如何解释它!

更新:

您的回答和 cmets 让我走上了正轨 :) 我还没有解决方案,但我注意到如果我将 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的文档:

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

【问题讨论】:

  • @assylias 这是一个只读的包装器:即它是一个包装ReadOnlyProperty的完全可写属性。此 API 旨在表示只能从包含它们的 bean 更改的值,但可以将 ReadOnlyProperty 公开为公共 API 以供外部观察。
  • 这是一个“包装器”:您仍然可以将其用作普通属性,但可以向客户端公开只读版本。根据文档:docs.oracle.com/javase/8/javafx/api/javafx/beans/property/…

标签: java javafx property-binding


【解决方案1】:

这是一个错误 (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 来计算绑定。我建议你报告这个错误。

【讨论】:

  • 这是一个相当完整的解释,感谢您深入了解它!附言你认为我需要提交错误报告吗?
  • 是的,我认为应该提交错误报告。请注意,将 true & true 更改为 false & true 时,and 也会发生同样的事情。我认为最好的解决方法是将binding.op1.equals(observable) 替换为(! binding.op2.equals(observable))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-12
  • 2018-12-10
  • 2012-08-06
  • 2015-01-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多