|
Re: StackOverflowError with databinding [message #1743552 is a reply to message #1743274] |
Fri, 16 September 2016 10:15 |
Xavipen Mising name Messages: 59 Registered: March 2011 |
Member |
|
|
I continue investigating the issue and i have found where is the problem.
I have a bean with some properties that can have a very High rate of updates. 500.000 or more a second. The bean bunches this updates and only calls its PropertyChangeListeners once every 500ms. However actual value of the property is changed very often.
On RAP, the client is set to pool every second to update the GUI. This triggers the execution of the ValueBinding.doUpdate(). So far so good and most of the times it is like this. However not always.
For extra information, this is how the ValueBinding is created:
IObservableValue modelElement = BeanProperties.value(field).observe(bean);
IObservableValue uiElement = WidgetProperties.text(SWT.Modify).observe(txtWidget);
bindingContext.bindValue(uiElement,
modelElement, targetToModelUpdateStrategy,
modelToTargetUpdateStrategy);
The issue is starts with the get value
// Get value
Object value = source.getValue()
This ends up calling the SimplePropertyObservableValue doGetValue method which calls the notifyIfChanged(null). This call to the notifyIfChanged if the one causing the stackOverflowError. The explanation is in comment lines in the code below
@Override
protected Object doGetValue() {
notifyIfChanged(null);
return property.getValue(source);
}
private void notifyIfChanged(ValueDiff diff) {
if (hasListeners()) {
Object oldValue = cachedValue;
//The property value is changed at a high rate of updates on a different thread.
//This causes a race condition.
// cachedValue updates to new value and fires the valueChange.
//second run this code gets call again but not fast enough so the property value has changed. This means fireValuChanged is called again.
// second run can repeat infinite times and causes StackOverflowError eventually.
Object newValue = cachedValue = property.getValue(source);
if (diff == null)
diff = Diffs.createValueDiff(oldValue, newValue);
if (!Util.equals(oldValue, newValue) || stale) {
stale = false;
fireValueChange(diff);
}
}
}
Normally the code above would be fine for most of the properties of a bean, but for this case it does not work. I guess it should be a save guard to avoid the recuesive loop and break it at some point to avoid the StackOverflowError.
for example, would do:
boolean getFiredUpdate = false;
@Override
protected Object doGetValue() {
if ( !getFiredUpdate ) {
getFiredUpdate = true;
notifyIfChanged(null);
}
getFiredUpdate = false;
return property.getValue(source);
}
The issue does not allways ends up in StackOverflowError but it can cause 30 recursives calls before the value is updated.
Could any one point me to an easy way of workaround this issue?
Should a bug report be open for this?
Regards,
Xavi
|
|
|
Powered by
FUDForum. Page generated in 0.02881 seconds