Databinding to mutable property stops in SimplePropertyObserverValue [message #1753185] |
Thu, 02 February 2017 14:25 |
Felix Hirsch Messages: 9 Registered: May 2016 Location: Aachen, Germany |
Junior Member |
|
|
Hi,
I'm using databinding and I found a problem in my application regarding the class org.eclipse.core.internal.databinding.property.value.SimplePropertyObserverValue.
The object I want to observe consists of many attributes and is part of a container object. I am observing changes to the inner object as property of the container.
In our implementation calling the setter method for the inner object mutates the inner object instead of replacing the object reference in the container.
This is not the usual approach and I can think of a better design but sometimes there can be a reason to act this way.
So perhaps the following problem can affect others too.
Here is an example which describes my problem:
public class MyContainer {
// implements property change support
private PropertyChangeSupport changeSupport = ...;
// this is the observable object
private MyData data;
public void addPropertyChangeListener(PropertyChangeListener l) {...}
public void removePropertyChangeListener(PropertyChangeListener l) {...}
public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {...}
public MyData getData() {...}
public MyData setData(MyData newValue) {
// create oldValue from member
MyData oldValue = data.clone();
// Mutate member instead of replacing the reference
data.setAttributes(newValue);
// fire change and provide correct old and new value
firePropertyChange("data", oldValue, data);
}
}
We call "container.setData" with an non equal new object and we have an observer created via "BeanProperties" and connected via "DataBindingContext" to the "container" object. The non equal old and new values are passed to "firePropertyChange".
When I debug the observation at one point I will end in the method SimplePropertyObservableValue.notifyIfChanged(ValueDiff<? extends T>) .
Here I can see a valid provided (non null) parameter "diff" of type "ValueDiff", which consist of exactly the objects which I provided to "firePropertyChange".
This method itself checks (again), if the objects differ from each other but uses a cached object reference for "oldValue" which refers to the same object (object identity) as the "data" member of my container and is therefore the same object as the "newValue" in the "diff" parameter. So here in this method the local variables "oldValue" and "newValue" will be references to the same object.
The objects provided by"diff.getOldValue()" and "diff.getNewValue()" are not considered for evaluation here and the observation stops as the result of "Util.equals(oldValue, newValue)" is true due to object identity.
If this method calls fireValueChanged and "diff" is NOT NULL it will be passed unmodified to all following observers. So for further evaluation the cached value is never considered anyway.
private void notifyIfChanged(ValueDiff<? extends T> diff) {
if (hasListeners()) {
// here diff.getOldValue() is not considered
T oldValue = cachedValue;
// here diff.getNewValue() is not considered
T newValue = cachedValue = property.getValue(source);
if (diff == null)
diff = Diffs.createValueDiff(oldValue, newValue);
if (!Util.equals(oldValue, newValue) || stale) {
stale = false;
// here diff is transmitted untouched in case it is not null
fireValueChange(Diffs.unmodifiableDiff(diff));
}
}
}
Is it correct that "diff.getOldValue()" and "diff.getNewValue()" are not considered in this method? Wouln't it be better to check, if an old value is provided by a non null "diff" parameter, and only if it is not provided, to use the cached value?
Thanks for your help
|
|
|
Powered by
FUDForum. Page generated in 0.03290 seconds