Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8127301

Is property's ChangeListener properly checking if the old and new value are not equal before calling the event?

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Incomplete
    • Icon: P4 P4
    • None
    • fx2.1
    • javafx

      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);
                      }
                  }
              });

            mheinrichs Michael Heinrichs (Inactive)
            tbee Tom Eugelink
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported: