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

TreeView / TreeItem API: Overriding getChildren() results in wrong behavior

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P4
    • tbd
    • 7u45, 8
    • javafx

    Description

      The TreeItem API exposes the getChildren() method. The method is not marked final, therefore, I can override it.
      The behavior I was expecting is that, if I override this method, I can pass a different observable list then the default one.

      The below JFXTreeItem extends TreeItem by overriding getChildren(). However, when used in a treeView, I do not get children displayed on screen.

      -----------------------------------------------------------------------------------------------------------------------------------
      public class JFXTreeItem<T> extends TreeItem<T> {

          private ObservableList<TreeItem<T>> children;

          public JFXTreeItem(T value, Node graphic) {
              super(value, graphic);
              children = FXCollections.observableArrayList();
          }


          @Override
          public ObservableList<TreeItem<T>> getChildren() {
              return children;
          }
      }
      -----------------------------------------------------------------------------------------------------------------------------------

      A closer look at the TreeItem code reveals two problems:
      1- getChildren() in TreeItem is setting a changeListener (which is private and not exposed to subclasses). Therefore any overriding of getChildren() will loose this changeListener. I am referring to the code below from TreeItem :

      public ObservableList<TreeItem<T>> getChildren()
        {
          if (this.children == null) {
            this.children = FXCollections.observableArrayList();
            this.children.addListener(this.childrenListener);
          }

          if (this.children.isEmpty()) return this.children;

          checkSortState();

          return this.children;
        }

      2- The code of TreeItem does not consistently call getChildren(), and at times will call <this.children>. Since the only exposed API is getChildren(), the value in this.children becomes irrelevant if the developer overrided getChildren(). As an example, the sort method :

       void sort()
        {
          sort(this.children, this.lastComparator, this.lastSortMode);
        }


      The only way where changing the children list works is by a hack through reflection. Something like the code below:

      ----------------------------------------------------------------------------------------------------------------------------------------
         public JFXTreeItem(T value, Node graphic) {
              super(value, graphic);

              ObservableList<TreeItem<T>> children = FXCollections.observableArrayList();

              try {
                  Field childrenField = TreeItem.class.getDeclaredField("children");
                  childrenField.setAccessible(true);
                  childrenField.set(this, children);

                  Field declaredField = TreeItem.class.getDeclaredField("childrenListener");
                  declaredField.setAccessible(true);
                  children.addListener((ListChangeListener<? super TreeItem<T>>) declaredField.get(this));

              } catch (Exception e) {
                  e.printStackTrace();
              }
      ------------------------------------------------------------------------------------------------------------------------------------------

      This code works, and items are displayed on the screen correctly.

      However, I don't think as an end developer I should resort to this tweak.
      Either the getChildren() remains available for overriding , and the internals of TreeItem get fixed.
      Or getChildren() should be declared final, and therefore the developer knows that overriding it won't work.


      Attachments

        Activity

          People

            Unassigned Unassigned
            rashajfx rasha (Inactive)
            Votes:
            1 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

              Created:
              Updated:
              Imported: