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

SortedList is fragile when Comparator is poorly implemented (ArrayIndexOutOfBoundsException)

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P3 P3
    • 9
    • 8u40
    • javafx
    • None

      When using SortedList on a ListView, it can happen that ListView won't update anymore, if the Comparator is poorly implemented. SortedList throws an ArrayIndexOutOfBoundsException.

      I've seen this with a more complex Comparator, which returned inconsistent results, e.g. o1 didn't always compare to o2 in the opposite way as the o2 compares to the o1.
      Implemeting well-behaved complex comparators is not always easy, so things like this can happen and I wonder if you can protect against it.

      (for some reason I didn't even seen any stacktrace in my real app, my ListView just stopped udating itself and I wondered what's up).

      Stacktrace:
      Exception in thread "JavaFX Application Thread" java.lang.ArrayIndexOutOfBoundsException: -5
      at javafx.collections.transformation.SortedList.findPosition(SortedList.java:318)
      at javafx.collections.transformation.SortedList.removeFromMapping(SortedList.java:359)
      at javafx.collections.transformation.SortedList.addRemove(SortedList.java:389)
      at javafx.collections.transformation.SortedList.sourceChanged(SortedList.java:105)
      at javafx.collections.transformation.TransformationList.lambda$getListener$16(TransformationList.java:106)
      at javafx.collections.transformation.TransformationList$$Lambda$77/10143061.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 javafx.collections.ModifiableObservableListBase.remove(ModifiableObservableListBase.java:183)


      Sample Code (just click the button a few times). You can also always return 1 from the comparator to trigger it immediately:


      import javafx.application.Application;
      import javafx.collections.FXCollections;
      import javafx.collections.ObservableList;
      import javafx.scene.Scene;
      import javafx.scene.control.Button;
      import javafx.scene.control.ListView;
      import javafx.scene.layout.VBox;
      import javafx.stage.Stage;

      import java.util.Random;

      public class TestApp3 extends Application {
          public static void main(String[] args) {
              launch(args);
          }

          @Override
          public void start(final Stage stage) throws Exception {

              ObservableList<Integer> list = FXCollections.observableArrayList();
              list.addAll(0, 2, 9, 6, 4, 5, 3, 1, 7, 8);

              ListView<Integer> listView = new ListView<>();
              listView.setItems(list.sorted((o1, o2) ->
                      // This is the bad comparator.
                      // if o1 = 7 and o2 == 8 returns 1
                      // if o1 = 8 and o2 == 7 also returns 1
                      // This seems to confuse SortedList
                      o1 < 5 ? o1.compareTo(o2) : 1));

              Button button = new Button("Click me");
              button.setOnAction(actionEvent -> {
                  // Remove the first item from list.
                  list.remove(0);
                  // Add new random integer between 0 (inclusive) and 10 (exclusive).
                  list.add(new Random().nextInt(10));
                  System.out.println(list);
              });

              Scene scene = new Scene(new VBox(listView, button));
              stage.setScene(scene);
              stage.show();
          }
      }

            vadim Vadim Pakhnushev
            cschudtjfx Christian Schudt (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported: