endless loop on property sync code

Richard Bair richard.bair at oracle.com
Tue Jan 17 10:32:09 PST 2012


Ya, sorry about that. Today being "Feature Freeze" seemed like a perfect day for JIRA to blow up :-). We've got a service request in with the Kenai guys, probably some file handle limit has been exceeded or something.

Richard

On Jan 17, 2012, at 9:56 AM, Tom Eugelink wrote:

> 
> I'll file a bug, but Jira reports it is locked (?), so I'll try later.
> 
> 
> On 17-1-2012 17:07, Richard Bair wrote:
>> I would have thought so. WIth an InvalidationListener we cannot make this check, because we don't actually know what the new value is unless we ask for the new value -- which would make everything eager. But for a change event we should only actually send a change event notification if it has actually changed. Sounds like a bug.
>> 
>> Richard
>> 
>> On Jan 17, 2012, at 5:35 AM, Tom Eugelink wrote:
>> 
>>> In an attempt to make some code "cheaper" I decided it could be a good idea to redundantly store the index next to the value it pointed to. Since this could save a fairly costly "getIndex" call.
>>> 
>>> So I ended up with two properties; one public value and one private index. Basically both denote the same value, so I needed to add sychronisation code:
>>> 
>>>        // react to changes of the value
>>>        this.valueObjectProperty.addListener(new ChangeListener<T>()
>>>        {
>>>            @Override
>>>            public void changed(ObservableValue<? extends T>  property, T oldValue, T newValue)
>>>            {
>>>                // get the value of the new index
>>>                Object lIdx = getDataProvider().getIndex(newValue);
>>>                if (lIdx == null) throw new IllegalArgumentException("Value does not exist " + newValue);
>>> 
>>>                // set the value
>>>                indexObjectProperty.setValue(lIdx);
>>>            }
>>>        });
>>> 
>>>        // react to changes of the index
>>>        this.indexObjectProperty.addListener(new ChangeListener<Object>()
>>>        {
>>>            @Override
>>>            public void changed(ObservableValue<? extends Object>  property, Object oldIndex, Object newIndex)
>>>            {
>>>                // get the value of the new index
>>>                T lValue = (T)getDataProvider().getValue(newIndex);
>>> 
>>>                // set the value
>>>                valueObjectProperty.setValue(lValue);
>>>            }
>>>        });
>>> 
>>> 
>>> This code results in an endless loop:
>>> Exception in Application start method
>>> Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
>>>    at com.sun.javafx.application.LauncherImpl.launchApplication1(Unknown Source)
>>>    at com.sun.javafx.application.LauncherImpl.access$000(Unknown Source)
>>>    at com.sun.javafx.application.LauncherImpl$1.run(Unknown Source)
>>>    at java.lang.Thread.run(Thread.java:662)
>>> Caused by: java.lang.StackOverflowError
>>>    at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(Unknown Source)
>>>    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(Unknown Source)
>>>    at javafx.beans.property.ObjectPropertyBase.fireValueChangedEvent(Unknown Source)
>>>    at javafx.beans.property.ObjectPropertyBase.markInvalid(Unknown Source)
>>>    at javafx.beans.property.ObjectPropertyBase.set(Unknown Source)
>>>    at javafx.beans.property.ObjectProperty.setValue(Unknown Source)
>>>    at jfxtras.scene.control.SpinnerX$1.changed(SpinnerX.java:147)
>>>    at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(Unknown Source)
>>>    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(Unknown Source)
>>>    at javafx.beans.property.ObjectPropertyBase.fireValueChangedEvent(Unknown Source)
>>>    at javafx.beans.property.ObjectPropertyBase.markInvalid(Unknown Source)
>>>    at javafx.beans.property.ObjectPropertyBase.set(Unknown Source)
>>>    at javafx.beans.property.ObjectProperty.setValue(Unknown Source)
>>>    at jfxtras.scene.control.SpinnerX$2.changed(SpinnerX.java:167)
>>>    at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(Unknown Source)
>>>    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(Unknown Source)
>>>    at javafx.beans.property.ObjectPropertyBase.fireValueChangedEvent(Unknown Source)
>>>    at javafx.beans.property.ObjectPropertyBase.markInvalid(Unknown Source)
>>> ...
>>> 
>>> 
>>> To solve this, I have to explicitly check if the value changed before the setValue (see "equals" below). Isn't Property suppose to do this?
>>> 
>>>        // react to changes of the value
>>>        this.valueObjectProperty.addListener(new ChangeListener<T>()
>>>        {
>>>            @Override
>>>            public void changed(ObservableValue<? extends T>  property, T oldValue, T newValue)
>>>            {
>>>                // get the value of the new index
>>>                Object lIdx = getDataProvider().getIndex(newValue);
>>>                if (lIdx == null) throw new IllegalArgumentException("Value does not exist " + newValue);
>>> 
>>>                // set the value
>>>                if (SpinnerX.equals(indexObjectProperty.getValue(), lIdx) == false)
>>>                {
>>>                    indexObjectProperty.setValue(lIdx);
>>>                }
>>>            }
>>>        });
>>> 
>>>        // react to changes of the index
>>>        this.indexObjectProperty.addListener(new ChangeListener<Object>()
>>>        {
>>>            @Override
>>>            public void changed(ObservableValue<? extends Object>  property, Object oldIndex, Object newIndex)
>>>            {
>>>                // get the value of the new index
>>>                T lValue = (T)getDataProvider().getValue(newIndex);
>>> 
>>>                // set the value
>>>                if (SpinnerX.equals(valueObjectProperty.getValue(), lValue) == false)
>>>                {
>>>                    valueObjectProperty.setValue(lValue);
>>>                }
>>>            }
>>>        });
>>> 
>>> 
>> 
> 
> 



More information about the openjfx-dev mailing list