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

Map- and SetExpression invalidation listeners cause eventual NPEs when removing themselves

XMLWordPrintable

      This is only really a problem because it's a pattern used by all of the Bindings and WeakListeners shipped by JavaFX—they remove themselves when their WeakReferences get collected.

      Here's a minimal repro:

      {code}
      import javafx.beans.InvalidationListener;
      import javafx.beans.Observable;
      import javafx.beans.property.SimpleMapProperty;
      import javafx.collections.FXCollections;

      public class SimpleMapPropertyRepro {

          public void runMe() {
              final SimpleMapProperty<String, String> m = new SimpleMapProperty<String, String>(FXCollections.<String, String>observableHashMap());
              m.addListener(new InvalidationListener() {
                  public void invalidated(Observable observable) {
                      m.removeListener(this);
                  }
              });

              m.addListener(new InvalidationListener() {
                  public void invalidated(Observable observable) {
                      // do nothing; a dummy listener needs to be added afterwards to trigger the NPE
                  }
              });

              m.put("world", "hello");
              m.put("world", "goodbye"); // NullPointerException
          }

      }
      {code}

      I've tracked the issue down to some code in MapExpressionHelper.Generic.removeListener which decrements the listener counter inside an if (!isLocked) check; the correct behavior I think is to decrement that counter outside the check. Same goes for SetExpressionHelper.Generic. (Interestingly, ListExpressionHelper.Generic.removeListener is already written with the decrement outside, so a SimpleListProperty doesn't produce the NPE when used in code similar to the above.)

            msladecek Martin Sládeček
            duke J. Duke
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported: