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

ArrayIndexOutOfBoundsException when listening to selection changes on TreeTableView

    XMLWordPrintable

Details

    • x86
    • linux_redhat_6.0

    Description

      FULL PRODUCT VERSION :
      java version "1.8.0_66"
      Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
      Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Linux knucklepuck 2.6.32-220.el6.x86_64 #1 SMP Tue Dec 6 19:48:22 GMT 2011 x86_64 x86_64 x86_64 GNU/Linux

      A DESCRIPTION OF THE PROBLEM :
      An ArrayIndexOutOfBoundsException is thrown on the JavaFX Application Thread when a TreeTableView's selection model is updated in response to a TreeItem being expanded.

      The TreeTableView is allowing multiple selections, and my application is trying to select all child nodes of a selected TreeItem when that TreeItem is expanded.

      There is a FilteredList that was created from the `getSelectedItems()` ObservableList of the TreeTableView's selection model. The exception is thrown when updating this FilteredList; removing the FilteredList prevents this exception from happening.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Select a non-leaf TreeItem that is a child of the root node in the TreeTableView.
      2. Rapidly expand/collapse the selected TreeItem by clicking quickly on the expand icon.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The FilteredList should be properly updated with the selected items in the TreeTableView.
      ACTUAL -
      An ArrayIndexOutOfBoundsException is thrown when expanding/collapsing a selected TreeItem.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Change: { [TreeItem [ value: Node 1-1 ]] added at 0 }
      Change: { [TreeItem [ value: Node 1-1 ]] added at 0 }
      Change: { [TreeItem [ value: Node 1-1 ]] added at 0 }
      Change: { [TreeItem [ value: Node 1-1 ]] added at 0 }
      Change: { [TreeItem [ value: Node 1-1 ]] added at 0 }
      Exception in thread "JavaFX Application Thread" java.lang.ArrayIndexOutOfBoundsException
              at java.lang.System.arraycopy(Native Method)
              at javafx.collections.transformation.FilteredList.addRemove(FilteredList.java:269)
              at javafx.collections.transformation.FilteredList.sourceChanged(FilteredList.java:144)
              at javafx.collections.transformation.TransformationList.lambda$getListener$15(TransformationList.java:106)
              at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
              at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
              at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
              at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.callObservers(ReadOnlyUnbackedObservableList.java:75)
              at javafx.scene.control.TreeTableView$TreeTableViewArrayListSelectionModel.handleSelectedCellsListChangeEvent(TreeTableView.java:3312)
              at javafx.scene.control.TreeTableView$TreeTableViewArrayListSelectionModel.lambda$new$125(TreeTableView.java:2313)
              at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
              at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
              at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
              at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
              at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
              at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
              at javafx.collections.transformation.SortedList.sourceChanged(SortedList.java:108)
              at javafx.collections.transformation.TransformationList.lambda$getListener$15(TransformationList.java:106)
              at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
              at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
              at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
              at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
              at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
              at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
              at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
              at javafx.collections.ModifiableObservableListBase.addAll(ModifiableObservableListBase.java:102)
              at com.sun.javafx.scene.control.SelectedCellsMap.addAll(SelectedCellsMap.java:146)
              at javafx.scene.control.TreeTableView$TreeTableViewArrayListSelectionModel.selectIndices(TreeTableView.java:2832)
              at javafx.scene.control.MultipleSelectionModel.selectRange(MultipleSelectionModel.java:176)
              at TreeTableViewSample.selectChildrenOfRows(TreeTableViewSample.java:96)
              at TreeTableViewSample.lambda$start$1(TreeTableViewSample.java:64)
              at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
              at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
              at javafx.beans.property.ReadOnlyIntegerWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:176)
              at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:142)
              at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
              at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:147)
              at javafx.scene.control.TreeTableView.setExpandedItemCount(TreeTableView.java:1088)
              at javafx.scene.control.TreeTableView.updateExpandedItemCount(TreeTableView.java:1861)
              at javafx.scene.control.TreeTableView.getExpandedItemCount(TreeTableView.java:1092)
              at com.sun.javafx.scene.control.behavior.TreeTableCellBehavior.getItemCount(TreeTableCellBehavior.java:72)
              at com.sun.javafx.scene.control.behavior.TableCellBehaviorBase.doSelect(TableCellBehaviorBase.java:110)
              at com.sun.javafx.scene.control.behavior.CellBehaviorBase.mouseReleased(CellBehaviorBase.java:159)
              at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
              at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
              at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
              at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
              at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
              at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
              at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
              at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
              at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
              at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
              at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
              at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
              at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
              at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
              at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
              at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
              at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
              at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
              at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
              at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
              at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
              at javafx.event.Event.fireEvent(Event.java:198)
              at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
              at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
              at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
              at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
              at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:352)
              at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
              at java.security.AccessController.doPrivileged(Native Method)
              at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:388)
              at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
              at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:387)
              at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
              at com.sun.glass.ui.View.notifyMouse(View.java:937)
              at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
              at com.sun.glass.ui.gtk.GtkApplication.lambda$null$49(GtkApplication.java:139)
              at java.lang.Thread.run(Thread.java:745)

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.util.*;

      import javafx.application.Application;
      import javafx.collections.*;
      import javafx.collections.transformation.*;
      import javafx.beans.property.ReadOnlyStringWrapper;
      import javafx.scene.*;
      import javafx.scene.control.*;
      import javafx.scene.control.TreeTableColumn.CellDataFeatures;
      import javafx.stage.Stage;

      public class TreeTableViewSample extends Application {

          public static void main(String[] args) {
              Application.launch(args);
          }

          @Override
          public void start(Stage stage) {
              final TreeItem<String> childNode1 = new TreeItem<>("Child Node 1");
              childNode1.getChildren().addAll(
                  new TreeItem<String>("Node 1-1"),
                  new TreeItem<String>("Node 1-2")
              );

              final TreeItem<String> root = new TreeItem<>("Root node");
              root.setExpanded(true);
              root.getChildren().add(childNode1);

              TreeTableColumn<String,String> column = new TreeTableColumn<>("Column");
              column.setPrefWidth(190);
              column.setCellValueFactory((CellDataFeatures<String, String> p) ->
                  new ReadOnlyStringWrapper(p.getValue().getValue()));

              final TreeTableView<String> treeTableView = new TreeTableView<>(root);
              treeTableView.getColumns().add(column);
              treeTableView.setPrefWidth(200);
              treeTableView.setShowRoot(true);
              treeTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

              // Select all children of expanded node.
              treeTableView.expandedItemCountProperty().addListener((observable, oldCount, newCount) -> {
                  if (newCount.intValue() > oldCount.intValue()) {
                      selectChildrenOfRows(treeTableView, treeTableView.getSelectionModel().getSelectedIndices());
                  }
              });

              filteredList = treeTableView.getSelectionModel().getSelectedItems().filtered(Objects::nonNull);
              filteredList.addListener((ListChangeListener.Change<? extends TreeItem<String>> change) -> {
                  System.out.printf("Change: %s\n", change);
              });

              final Scene scene = new Scene(new Group(), 200, 400);
              Group sceneRoot = (Group)scene.getRoot();
              sceneRoot.getChildren().add(treeTableView);

              stage.setTitle("Tree Table View Samples");
              stage.setScene(scene);
              stage.show();
          }

          private FilteredList<TreeItem<String>> filteredList;

          private void selectChildrenOfRows(TreeTableView<String> table, Collection<Integer> selectedRows) {
              for (int index: selectedRows) {
                  TreeItem<String> item = table.getTreeItem(index);

                  if (item != null && item.isExpanded() && !item.getChildren().isEmpty()) {
                      int startIndex = index + 1;
                      int maxCount = startIndex + item.getChildren().size();

                      table.getSelectionModel().selectRange(startIndex, maxCount);
                  }
              }
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Don't create a FilteredList from the selectedItems property of a TreeTableView.

      Attachments

        Issue Links

          Activity

            People

              jgiles Jonathan Giles
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: