Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IllegalArgumentException: length must not be negative in DataCommunicator with undefined size #9988

Closed
probert94 opened this issue Feb 8, 2021 · 4 comments · Fixed by #10020

Comments

@probert94
Copy link

Description of the bug / feature

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

Minimal reproducible example

  1. Create a TextField for the searchTerm:
TextField tfSearchTerm = new TextField("Search");
tfSearchTerm.addValueChangeListener(e -> grid.getDataProvider().refreshAll());
  1. Create a List of at least 200 items
  2. Create an AbstractBackEndDataProvider for these items, use the 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());
    }
}
  1. Create a Grid with this DataProvider and call grid.getDataCommunicator().setDefinedSize(false)
  2. Open the web page, scroll down so that a new block of data is fetched and then insert a searchTerm which only matches a few items.

Expected behavior

The Grid should show the filtered items

Actual behavior

A java.lang.IllegalArgumentException: length must not be negative is thrown instead

Additional information:

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

Versions:

- Vaadin version: 18.0.5
- Java version: 11.0.10 (Adopt OpenJDK)
- OS version: Windows 10
@pleku
Copy link
Contributor

pleku commented Feb 9, 2021

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.

@probert94
Copy link
Author

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.

@pleku
Copy link
Contributor

pleku commented Feb 9, 2021

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.

@ziza
Copy link

ziza commented Feb 10, 2021

Reproducible example in vaadin/vaadin-grid#2128

mshabarov added a commit to vaadin/flow-components that referenced this issue Feb 14, 2021
Adds a regression test to verify the case when the items are bound to Grid lazily with unknown items count and the filter is being applied to items in the middle of scrolling.

Related-to: vaadin/flow#9988
pleku pushed a commit to vaadin/flow-components that referenced this issue Feb 15, 2021
Adds a regression test to verify the case when the items are bound to Grid lazily with unknown items count and the filter is being applied to items in the middle of scrolling.

Related-to: vaadin/flow#9988
vaadin-bot pushed a commit to vaadin/flow-components that referenced this issue Feb 15, 2021
Adds a regression test to verify the case when the items are bound to Grid lazily with unknown items count and the filter is being applied to items in the middle of scrolling.

Related-to: vaadin/flow#9988
mshabarov pushed a commit to vaadin/flow-components that referenced this issue Feb 16, 2021
#647)

Adds a regression test to verify the case when the items are bound to Grid lazily with unknown items count and the filter is being applied to items in the middle of scrolling.

Related-to: vaadin/flow#9988
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants