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

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

    Details

    • Type: Bug
    • Status: Open
    • Priority: P4
    • Resolution: Unresolved
    • Affects Version/s: 7u45, 8
    • Fix Version/s: tbd
    • Component/s: javafx
    • Labels:

      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

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

              Dates

              • Created:
                Updated:
                Imported: