I have a Grid with a DataCommunicator with unknown size (setDefinedSize(false)).
I am using a TextField to search for (i.e. filter) the items.
When I scroll down until a new "block" of data is fetched, and I insert a filter string, which limits the result to a few items only, I am getting a IllegalArgumentException: length must not be negative
TextField for the searchTerm:TextField tfSearchTerm = new TextField("Search");
tfSearchTerm.addValueChangeListener(e -> grid.getDataProvider().refreshAll());
TextFields value as a filter. Example:new AbstractBackEndDataProvider<Person, Void>() {
protected Stream<Person> fetchFromBackEnd(Query<Person, Void> query) {
List<Person> filteredPersons = getFilteredItems();
return filteredPersons.stream()
.skip(Math.min(filteredPersons.size(), query.getOffset()))
.limit(query.getLimit());
}
protected int sizeInBackEnd(Query<Person, Void> query) {
return getFilteredItems().size();
}
private List<Person> getFilteredItems() {
String searchTerm = tfSearchTerm.getValue();
return items.stream()
.filter(p -> p.getName().contains(searchTerm))
.collect(Collectors.toList());
}
}
Grid with this DataProvider and call grid.getDataCommunicator().setDefinedSize(false)The Grid should show the filtered items
A java.lang.IllegalArgumentException: length must not be negative is thrown instead
The problem seems to be, that the previous fetch loaded items with an offset, which is larger then the size of the filtered list.
For example:
items 50 to 200 are loaded. After applying the filter there are only 2 items left.
Inside DataCommunicator#flush the requestedRange therefore goes from -150 to 50 and the assumedSize is later calculated based on that requestedRange (Line 1103). The calculated assumedSize is then negative (-148 in this case) and results in this error.
I think, that instead of using requestedRange, effectiveRequested should be used, which is limited to 0 to assumedSize
- Vaadin version: 18.0.5
- Java version: 11.0.10 (Adopt OpenJDK)
- OS version: Windows 10
Just first noting that you don't need to create an AbstractBackEndDataProvider but just use the setItems shorthand which takes only the fetch query callback - or are you switching between defined and undefined size ? Using DataCommunicator API works but it is discouraged and I would ask you to use grid.getLazyDataView().setItemCountUnknown(); and grid.getLazyDataView().setItemCountFromDataProvider(); instead.
For this example I would not need the AbstractBackEndDataProvider, but I am using it the real project, since I have to load entries from a database. I am not sure, if the same problem can be reproduced without the AbstractBackEndDataProvider.
I would ask you to use grid.getLazyDataView().setItemCountUnknown(); and grid.getLazyDataView().setItemCountFromDataProvider(); instead.
I will use this API from now on, did not notice it until now.
I am not sure, if the same problem can be reproduced without the AbstractBackEndDataProvider.
My assumption is that it does not matter, just wanted to mention it anyway.
We're trying to figure out if there is an way to workaround this, but no idea yet. As this is very core use case, marking this as a blocker issue for now.
Reproducible example in https://github.com/vaadin/vaadin-grid/issues/2128