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

ListPropertyBase: doesn't notify changeListener in bidi-binding

    XMLWordPrintable

Details

    Description

      Below are some failing tests around notification of changeListeners

      Basic setup: newList.equals(oldList) && newList != oldList
      Expected behaviour: changeListener is notified
      Actual behaviour: changeListener is notified only if ListProperty not in bidi-binding. Traced down to being a single listener vs. multiple listeners

      Digging a bit reveals that ListPropertyBase.set(...) and ListExpressionHelper.SingleChange.fireValueChangeEvent(..) test against identity resulting in expected behaviour, while GenericChange.fireValueChangeEvent(...) tests against equality, resulting in failure to notify.

      Though I think that the bidi tests will behave as expected when GenericChange is fixed I kept them just in case there's yet another issue
          /**
           * Test notification of changeListeners on setting a list that equals the old
           * value but is a different instance.
           *
           * Passes without bidi-binding.
           */
          @Test
          public void testListPropertyNotificationSingleListener() {
              ObservableList<String> initialValue = createObservableList(false);
              ListProperty<String> property = new SimpleListProperty<>(initialValue);
              ChangeReport report = new ChangeReport(property);
              ObservableList<String> otherValue = createObservableList(false);
              assertTrue("sanity: FXCollections returns a new instance", otherValue != initialValue);
              property.set(otherValue);
              assertEquals(1, report.getEventCount());
              assertSame(initialValue, report.getLastOldValue());
              assertSame(otherValue, report.getLastNewValue());
          }
          
          /**
           * Bug: ListPropertyBase fails to notify change listeners if multiple
           * listeners registered
           */
          @Test
          public void testListPropertyNotificationMultipleListener() {
              ObservableList<String> initialValue = createObservableList(false);
              ListProperty<String> property = new SimpleListProperty<>(initialValue);
              ChangeReport report = new ChangeReport(property);
              ChangeReport otherListener = new ChangeReport(property);
              ObservableList<String> otherValue = createObservableList(false);
              assertTrue("sanity: FXCollections returns a new instance", otherValue != initialValue);
              property.set(otherValue);
              assertEquals(1, report.getEventCount());
              assertSame(initialValue, report.getLastOldValue());
              assertSame(otherValue, report.getLastNewValue());
          }
          
          /**
           * Asserts bidi binding between source/target ListPropery
           * (too much for a decent test, but then ..)
           * - value of target is synched to source
           * - ChangeListener on target is notified on binding
           *
           * @param withData
           */
          protected void assertListPropertyBidiBinding(boolean withData) {
              ObservableList<String> initialValue = createObservableList(withData);
              ListProperty<String> target = new SimpleListProperty<>(initialValue);
              ObservableList<String> sourceValue = createObservableList(withData);
              ListProperty<String> source = new SimpleListProperty<>(sourceValue);
              ChangeReport targetReport = new ChangeReport(target);

              target.bindBidirectional(source);
              
              assertSame("bidi binding updates", target.get(), source.get());
              assertSame("property is target of bidi", sourceValue, target.get());
              assertSame("other is unchanged", sourceValue, source.get());
              // this passes: listeners on target are notified installing the bidibinding
              assertEquals("change listener on property must be notified", 1, targetReport.getEventCount());
              
              targetReport.clear();
              ChangeReport sourceReport = new ChangeReport(source);
              ObservableList<String> thirdValue = createObservableList(withData);
              source.set(thirdValue);
              assertSame("source value taken", thirdValue, source.get());
              // was meant as sanity testing .. but the bidibinding prevents
              // the notification that is just fine if unbound ... see test above
              // assertEquals("sanity: source listener notified", 1, sourceReport.getEventCount());
              assertSame("property must be updated to new value of other", thirdValue, target.get());
              // this fails: listeners on target are not notified after updating the source of the bidibinding
              assertEquals("change listener on property must be notified", 1, targetReport.getEventCount());
          }

          @Test
          public void testListPropertyBidiBindingNotificationListEmpty() {
              assertListPropertyBidiBinding(false);
          }
          
          @Test
          public void testListPropertyBidiBindingNotificationListWithData() {
              assertListPropertyBidiBinding(true);
          }
          
          static final String[] DATA = {"just", "some", "content"};
          protected ObservableList<String> createObservableList(boolean withData) {
              return withData ? FXCollections.observableArrayList(DATA) : FXCollections.observableArrayList();
          }

      Attachments

        Activity

          People

            msladecek Martin Sládeček
            fastegal Jeanette Winzenburg
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:
              Imported: