FULL PRODUCT VERSION :
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
The problem is not OS specific.
A DESCRIPTION OF THE PROBLEM :
Creating a bidirectional binding for a read-only wrapper (e.g. by using ReadOnlyMapWrapper.bindBidirectional(Property<ObservableMap<K, V>> other)) does not work properly, i.e. the target property value is not properly updated if the source read-only wrapper's value is changed.
The reason is that the TypedGenericBidirectionalBinding, which is ultimately used to realize the bidirectional binding (through several indirections), performs the following check to infer which property is source and which is target when observing a change:
if (property1 == sourceProperty) {
property2.setValue(newValue);
} else {
property1.setValue(newValue);
}
As all read-only wrappers (like ReadOnlyMapWrapper) use their nested read-only property as source of change notifications (they delegate their fire* methods to it), property1 == sourceProperty will never be true for a read-only wrapper. In case of a ReadOnlyMapWrapper, the check would have to be ((ReadOnlyMapWrapper)property1).getReadOnlyProperty() == sourceProperty() to succeed.
ADDITIONAL REGRESSION INFORMATION:
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Create two ReadOnlyMapWrapper instances.
2) Bind first bidirectional to second.
3) Update value of the first and observe that the second is not updated.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The second property should be updated to hold the same value as the first.
ACTUAL -
The second property contains a different value, namely the old/initial one.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
@Test
public void bidirectionalBinding() {
MapProperty<Integer, String> property1 = new ReadOnlyMapWrapperEx<>(new ObservableMapWrapper<>(new HashMap<Integer, String>()));
MapProperty<Integer, String> property2 = new ReadOnlyMapWrapperEx<>(new ObservableMapWrapper<>(new HashMap<Integer, String>()));
property2.bindBidirectional(property1);
// change value of first property
ObservableMap<Integer, String> newValue = new ObservableMapWrapper<>(new HashMap<Integer, String>());
newValue.put(1, "1-1");
property1.set(newValue);
assertEquals(newValue, property1.get());
assertEquals(newValue, property2.get());
assertEquals(property1, property2);
// change value of second property
newValue = new ObservableMapWrapper<>(new HashMap<Integer, String>());
newValue.put(2, "2-1");
property2.set(newValue);
assertEquals(newValue, property1.get());
assertEquals(newValue, property2.get());
assertEquals(property1, property2);
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
There is no direct workaround, except replacing the read-only wrapper classes with own implementations that provide proper bidirectional bindings.
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
The problem is not OS specific.
A DESCRIPTION OF THE PROBLEM :
Creating a bidirectional binding for a read-only wrapper (e.g. by using ReadOnlyMapWrapper.bindBidirectional(Property<ObservableMap<K, V>> other)) does not work properly, i.e. the target property value is not properly updated if the source read-only wrapper's value is changed.
The reason is that the TypedGenericBidirectionalBinding, which is ultimately used to realize the bidirectional binding (through several indirections), performs the following check to infer which property is source and which is target when observing a change:
if (property1 == sourceProperty) {
property2.setValue(newValue);
} else {
property1.setValue(newValue);
}
As all read-only wrappers (like ReadOnlyMapWrapper) use their nested read-only property as source of change notifications (they delegate their fire* methods to it), property1 == sourceProperty will never be true for a read-only wrapper. In case of a ReadOnlyMapWrapper, the check would have to be ((ReadOnlyMapWrapper)property1).getReadOnlyProperty() == sourceProperty() to succeed.
ADDITIONAL REGRESSION INFORMATION:
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Create two ReadOnlyMapWrapper instances.
2) Bind first bidirectional to second.
3) Update value of the first and observe that the second is not updated.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The second property should be updated to hold the same value as the first.
ACTUAL -
The second property contains a different value, namely the old/initial one.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
@Test
public void bidirectionalBinding() {
MapProperty<Integer, String> property1 = new ReadOnlyMapWrapperEx<>(new ObservableMapWrapper<>(new HashMap<Integer, String>()));
MapProperty<Integer, String> property2 = new ReadOnlyMapWrapperEx<>(new ObservableMapWrapper<>(new HashMap<Integer, String>()));
property2.bindBidirectional(property1);
// change value of first property
ObservableMap<Integer, String> newValue = new ObservableMapWrapper<>(new HashMap<Integer, String>());
newValue.put(1, "1-1");
property1.set(newValue);
assertEquals(newValue, property1.get());
assertEquals(newValue, property2.get());
assertEquals(property1, property2);
// change value of second property
newValue = new ObservableMapWrapper<>(new HashMap<Integer, String>());
newValue.put(2, "2-1");
property2.set(newValue);
assertEquals(newValue, property1.get());
assertEquals(newValue, property2.get());
assertEquals(property1, property2);
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
There is no direct workaround, except replacing the read-only wrapper classes with own implementations that provide proper bidirectional bindings.
- duplicates
-
JDK-8089557 bindBidirection works for ReadOnly*Wrapper incorrectly
-
- Resolved
-