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

Invalid Change object when listening to selected items of a table

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: P4
    • Resolution: Fixed
    • Affects Version/s: 8u20
    • Fix Version/s: 8u40
    • Component/s: javafx
    • Labels:
    • Environment:

      Fedora release 20 (Heisenbug)
      java version "1.8.0_20"
      Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
      Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)

      Description

      When adding a listener to a table's selection, the ChangeObject passed into the listener will have wasRemoved() == true, but calling getRemoved() will result in an exception.

      The following example illustrates the bug: It will create a table of 50 persons. When a column header is clicked, the following exception is thrown:

      Exception in thread "JavaFX Application Thread" java.util.NoSuchElementException
      at java.util.AbstractList$Itr.next(AbstractList.java:364)
      at java.util.AbstractCollection.toString(AbstractCollection.java:461)
      at java.lang.String.valueOf(String.java:2981)
      at java.io.PrintStream.println(PrintStream.java:821)
      at prv.rli.codetest.TableViewSelectionBug.selectionChanged(TableViewSelectionBug.java:67)
      at prv.rli.codetest.TableViewSelectionBug$$Lambda$97/947243259.onChanged(Unknown Source)
      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.TableView$TableViewArrayListSelectionModel.handleSelectedCellsListChangeEvent(TableView.java:2848)
      at javafx.scene.control.TableView$TableViewArrayListSelectionModel.lambda$new$47(TableView.java:1984)
      at javafx.scene.control.TableView$TableViewArrayListSelectionModel$$Lambda$81/1505799527.onChanged(Unknown Source)
      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$16(TransformationList.java:106)
      at javafx.collections.transformation.TransformationList$$Lambda$83/1095537600.onChanged(Unknown Source)
      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 com.sun.javafx.collections.ObservableListWrapper.clear(ObservableListWrapper.java:157)
      at com.sun.javafx.scene.control.SelectedCellsMap.clear(SelectedCellsMap.java:183)
      at javafx.scene.control.TableView$TableViewArrayListSelectionModel.quietClearSelection(TableView.java:2561)
      at javafx.scene.control.TableView$TableViewArrayListSelectionModel.clearSelection(TableView.java:2557)
      at javafx.scene.control.TableView$TableViewArrayListSelectionModel$3.onChanged(TableView.java:2036)
      at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
      at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
      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 com.sun.javafx.collections.ObservableListWrapper.clear(ObservableListWrapper.java:157)
      at prv.rli.codetest.TableViewSelectionBug.sortOrderChanged(TableViewSelectionBug.java:60)
      at prv.rli.codetest.TableViewSelectionBug.lambda$0(TableViewSelectionBug.java:34)
      at prv.rli.codetest.TableViewSelectionBug$$Lambda$96/411038885.onChanged(Unknown Source)
      at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
      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.setAll(ModifiableObservableListBase.java:90)
      at javafx.collections.ObservableListBase.setAll(ObservableListBase.java:250)
      at com.sun.javafx.scene.control.skin.TableColumnHeader.sortColumn(TableColumnHeader.java:793)
      at com.sun.javafx.scene.control.skin.TableColumnHeader.lambda$static$54(TableColumnHeader.java:241)
      at com.sun.javafx.scene.control.skin.TableColumnHeader$$Lambda$153/1625749590.handle(Unknown Source)
      at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
      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.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:3724)
      at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3452)
      at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1728)
      at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2461)
      at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:348)
      at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:273)
      at java.security.AccessController.doPrivileged(Native Method)
      at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:382)
      at com.sun.glass.ui.View.handleMouseEvent(View.java:553)
      at com.sun.glass.ui.View.notifyMouse(View.java:925)
      at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
      at com.sun.glass.ui.gtk.GtkApplication.lambda$null$45(GtkApplication.java:126)
      at com.sun.glass.ui.gtk.GtkApplication$$Lambda$42/1099983479.run(Unknown Source)
      at java.lang.Thread.run(Thread.java:745)

      Here's the example:
      package prv.rli.codetest;

      import javafx.application.Application;
      import javafx.beans.property.SimpleStringProperty;
      import javafx.beans.property.StringProperty;
      import javafx.collections.FXCollections;
      import javafx.collections.ListChangeListener.Change;
      import javafx.collections.ObservableList;
      import javafx.scene.Scene;
      import javafx.scene.control.TableColumn;
      import javafx.scene.control.TableView;
      import javafx.scene.control.cell.PropertyValueFactory;
      import javafx.stage.Stage;

      public class TableViewSelectionBug extends Application {

      ObservableList<Person> items = FXCollections.observableArrayList();
      TableView<Person> table = new TableView<Person>();

      public TableViewSelectionBug() {
      }

      @Override
      public void start(Stage primaryStage) throws Exception {
      table.setItems(items);
      TableColumn<Person, String> firstNameCol = new TableColumn<Person, String>("First Name");
      firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
      TableColumn<Person, String> lastNameCol = new TableColumn<Person, String>("Last Name");
      lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
      table.getColumns().setAll(firstNameCol, lastNameCol);
      table.setSortPolicy(this::sortPolicy);
      table.getSortOrder().addListener((Change<? extends TableColumn<Person, ?>> c) -> { sortOrderChanged(); });
      table.getSelectionModel().getSelectedItems().addListener(this::selectionChanged);

              addPersons();

              Scene scene = new Scene(table, 400, 400);
              primaryStage.setScene(scene);
              primaryStage.show();
      }

      // simulate server call, usually this would take sort order property into account
      private void addPersons() {
      for (int i = 0; i < 50; i++) {
      Person p = new Person();
      int idx = items.size();
      p.setFirstName(idx + " John");
      p.setLastName(idx + "Doe");
      items.add(p);
      }
      }

          private Boolean sortPolicy(TableView<Person> table) {
           return true;
          }
          
          private void sortOrderChanged() {
           items.clear();
           addPersons();
          }
          
      private void selectionChanged(Change<? extends Person> c) {
      while (c.next()) {
      if (c.wasRemoved()) {
      System.out.println(c.getRemoved());
      // ^^^ will throw Exception in thread "JavaFX Application Thread" java.util.NoSuchElementException, when a column header is clicked
      }
      }
      }

          public static void main(String[] args) {
              launch(args);
          }
          
          public class Person {
              private StringProperty firstName;
              public void setFirstName(String value) { firstNameProperty().set(value); }
              public String getFirstName() { return firstNameProperty().get(); }
              public StringProperty firstNameProperty() {
                  if (firstName == null) firstName = new SimpleStringProperty(this, "firstName");
                  return firstName;
              }
              
              private StringProperty lastName;
              public void setLastName(String value) { lastNameProperty().set(value); }
              public String getLastName() { return lastNameProperty().get(); }
              public StringProperty lastNameProperty() {
                  if (lastName == null) lastName = new SimpleStringProperty(this, "lastName");
                  return lastName;
              }
          }
      }

        Attachments

          Activity

            People

            Assignee:
            jgiles Jonathan Giles
            Reporter:
            rlichtenbjfx Robert Lichtenberger (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            7 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved:
              Imported: