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

ChangeListener is not triggered when the InvalidationListener is removed

XMLWordPrintable

    • b17
    • generic
    • generic

        ADDITIONAL SYSTEM INFORMATION :
        Tested with:
        JavaFX version "20.0.2"
        and
        JavaFX version "21.0.2"
        OS name : Microsoft Windows 10 Professional
        Version : 10.0.19045 build 19045

        A DESCRIPTION OF THE PROBLEM :
        For JavaFX version 21.0.2 onwards, when there is a mix of ChangeListeners and InvalidationListeners added to an ObjectProperty, in some particular cases the ChangeListeners are no longer triggered once the InvalidationListener is removed while it is triggered.
        If we remove the InvalidationListener within it's call, the currentValue (class Generic) in ExpressionHelper is reset which can cause issues for further changes in the ObjectProperty's value. This is not the case for JavaFX version 20.0.2 (or below) and we believe that this issue might be triggered by the correction of another issue https://bugs.openjdk.org/browse/JDK-8224260.

        In the code snippet provided we start with the objectProperty's value as BASELINE_CENTER.
        We then set the objectProperty's value as BOTTOM_LEFT, the call to InvalidationListener removes the listener which resets the currentValue (class Generic) in ExpressionHelper to BASELINE_CENTER. The call to the ChangeListener will print "LISTENER CALLED".
        Next when we set the objectProperty's value as BASELINE_CENTER, the call to ChangeListeners considers that there are no more changes as the currentValue is also BASELINE_CENTER, failing to print "LISTENER CALLED" for the second time. Whereas for JavaFX version 20.0.2 (or below), the "LISTENER CALLED" is printed twice as the objectPropert's value is set twice.

        REGRESSION : Last worked in version 20

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Run the code snippet with JavaFX version 21.0.2 (or above) and with JavaFX version 20.0.2 (or below) for comparison.
        The line LISTENER CALLED should be printed for every change in the value of the ObjectProperty. In case of our code snippet, it should be printed twice as we set the value of the objectProperty twice.
        If we comment out the line "observable.removeListener(this);" while testing in JavaFX version 21.0.2, it works as expected.

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        LISTENER CALLED
        LISTENER CALLED
        ACTUAL -
        LISTENER CALLED

        ---------- BEGIN SOURCE ----------
        public static void main(String[] args) {
                ObjectProperty<Pos> objectProperty = new SimpleObjectProperty<>(Pos.BASELINE_CENTER);

                objectProperty.addListener((observable, oldValue, newValue) -> System.out.println("LISTENER CALLED"));
                objectProperty.addListener(new InvalidationListener() {
                    @Override
                    public void invalidated(Observable observable) {
                        observable.removeListener(this);
                    }
                });

                objectProperty.set(Pos.BOTTOM_LEFT); // Trigger the ChangeListener and display "LISTENER CALLED"
                objectProperty.set(Pos.BASELINE_CENTER); // This will not trigger the ChangeListener. No problem in JavaFX <= 20. No problem with value other than Pos.BASELINE_CENTER
            }
        ---------- END SOURCE ----------

        FREQUENCY : always


              jhendrikx John Hendrikx
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

                Created:
                Updated:
                Resolved: