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
。我建议你报告这个错误。
我在使用 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
。我建议你报告这个错误。