A DESCRIPTION OF THE PROBLEM :
There is a FilteredList created based on a SortedList that is based on an ObservableList. ObservableList contains duplicate elements (compareTo() returns 0 for them). When removing almost all elements from the base ObservableList using the removeAll() method an IndexOutOfBoundsException is raised in the FilteredList.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create an empty ObservableList
2. Create SortedList based on ObservableList with natural ordering
3. Create FilteredList based on SortedList
4. Add some elements in ObseravbleList with duplicates (for example, 10+ duplicates for each element)
5. Remove 90%+ elements from ObservableList using removeAll() method
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No exception is raised.
ACTUAL -
java.lang.IndexOutOfBoundsException is raised.
---------- BEGIN SOURCE ----------
public class FilteredListTest {
private static volatile boolean platformInitialized = false;
@Test(timeout = 1000)
public void test() throws ExecutionException, InterruptedException {
final var UNIQUE_ITEMS_NUM = 5;
final var REPEAT_ITEMS = 10;
var res = new CompletableFuture<>();
Runnable test = () -> {
platformInitialized = true;
Thread.currentThread().setUncaughtExceptionHandler((t, e) -> res.completeExceptionally(e));
// Lists
ObservableList<Integer> list = FXCollections.observableArrayList();
var sorted = list.sorted();
var filtered = new FilteredList<>(sorted);
// Filling the list
for (var i = 1; i <= UNIQUE_ITEMS_NUM; i++) {
for (var j = 0; j < REPEAT_ITEMS; j++) {
list.add(i);
}
}
Assert.assertEquals(UNIQUE_ITEMS_NUM * REPEAT_ITEMS, list.size());
// Removing items
var toRemove = IntStream
.range(1, UNIQUE_ITEMS_NUM)
.boxed()
.collect(Collectors.toList());
Assert.assertEquals(UNIQUE_ITEMS_NUM - 1, toRemove.size());
list.removeAll(toRemove);
res.complete(filtered.size());
};
if (platformInitialized) {
Platform.runLater(test);
} else {
Platform.startup(test);
}
Assert.assertEquals(REPEAT_ITEMS, res.get());
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Remove elements one by one:
toRemove.forEach(list::removeAll);
instead
list.removeAll(toRemove);
FREQUENCY : often
There is a FilteredList created based on a SortedList that is based on an ObservableList. ObservableList contains duplicate elements (compareTo() returns 0 for them). When removing almost all elements from the base ObservableList using the removeAll() method an IndexOutOfBoundsException is raised in the FilteredList.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create an empty ObservableList
2. Create SortedList based on ObservableList with natural ordering
3. Create FilteredList based on SortedList
4. Add some elements in ObseravbleList with duplicates (for example, 10+ duplicates for each element)
5. Remove 90%+ elements from ObservableList using removeAll() method
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No exception is raised.
ACTUAL -
java.lang.IndexOutOfBoundsException is raised.
---------- BEGIN SOURCE ----------
public class FilteredListTest {
private static volatile boolean platformInitialized = false;
@Test(timeout = 1000)
public void test() throws ExecutionException, InterruptedException {
final var UNIQUE_ITEMS_NUM = 5;
final var REPEAT_ITEMS = 10;
var res = new CompletableFuture<>();
Runnable test = () -> {
platformInitialized = true;
Thread.currentThread().setUncaughtExceptionHandler((t, e) -> res.completeExceptionally(e));
// Lists
ObservableList<Integer> list = FXCollections.observableArrayList();
var sorted = list.sorted();
var filtered = new FilteredList<>(sorted);
// Filling the list
for (var i = 1; i <= UNIQUE_ITEMS_NUM; i++) {
for (var j = 0; j < REPEAT_ITEMS; j++) {
list.add(i);
}
}
Assert.assertEquals(UNIQUE_ITEMS_NUM * REPEAT_ITEMS, list.size());
// Removing items
var toRemove = IntStream
.range(1, UNIQUE_ITEMS_NUM)
.boxed()
.collect(Collectors.toList());
Assert.assertEquals(UNIQUE_ITEMS_NUM - 1, toRemove.size());
list.removeAll(toRemove);
res.complete(filtered.size());
};
if (platformInitialized) {
Platform.runLater(test);
} else {
Platform.startup(test);
}
Assert.assertEquals(REPEAT_ITEMS, res.get());
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Remove elements one by one:
toRemove.forEach(list::removeAll);
instead
list.removeAll(toRemove);
FREQUENCY : often
- relates to
-
JDK-8123362 AIOOBE on SortedList based on FilteredList with duplicate entries
- Resolved