vaadin / framework

Vaadin 6, 7, 8 is a Java framework for modern Java web applications.
http://vaadin.com/
Other
1.77k stars 728 forks source link

V8 grid renders a row for the same item twice #12411

Closed Leaghte closed 1 year ago

Leaghte commented 2 years ago

We have a SpringBoot application using Vaadin 8.14.0 framework with Vaadin Push and Vaadin EventBus and we have encountered a problem where a grid renders a single item twice.

The grid uses a data provider which fetched items from the DB. The view in which the grid is placed listens for item change events delivered via EventBus and refreshes items in the grid's data provider. At the first glance everything works as expected until a user starts to sort and scroll the grid items during the time events are continuously received and processed. When doing that, duplicate rows might appear. Selecting such a row selects the 'original' as well.

I prepared a simple demo application to demonstrate the issue and also a GIF file for easier envision.

Peek 2021-09-23 16-01

Link to the demo project: https://github.com/Leaghte/vaading-grid-demo

How to replicate: Start the application, press 'Start live updates' and then start scrolling and sorting the grid items. Duplicate rows are easily spotted since they are always missing the 'Status' image.

TatuLund commented 2 years ago

Usually this issue occurs when you have faulty equals / hashCode implementation. Vaadin requires that change of the property value will not change object identity.

Your code looks ok by brief look

https://github.com/Leaghte/vaading-grid-demo/blob/main/src/main/java/software/netcore/vaadingriddemo/User.java#L35

But you use Lombok Builder

https://github.com/Leaghte/vaading-grid-demo/blob/main/src/main/java/software/netcore/vaadingriddemo/User.java#L11

I suspect that it actually during compile time replaces hashCode and equals with something and your implementation is not used.

See Lombok doc: https://projectlombok.org/features/Builder

"Each listed generated element will be silently skipped if that element already exists (disregarding parameter counts and looking only at names). This includes the builder itself: If that class already exists, lombok will simply start injecting fields and methods inside this already existing class, unless of course the fields / methods to be injected already exist. You may not put any other method (or constructor) generating lombok annotation on a builder class though; for example, you can not put @EqualsAndHashCode on the builder class."

Leaghte commented 2 years ago

Thanks for the reply. We know that Vaadin Grid needs objects to have equals / hashCode contract implemented properly to uniquely identify them. It was the first thing i checked when the issue occurred whether another developer hadn't changed that by mistake.

We use Lombok for a quite long time already and we have never run into any issue regarding having lombok overriding our equals / haschode implementation. Since we use those a lot, we would definitely run into a problem sooner or later. However i checked the compiled User class from the demo project anyway and Lombok indeed does not replace explicitly implemented equals / hashcode methods.

I have even checked the KeyMapper used by DataCommunicator if i would be able to locate duplicates, however this would be only possible when equals/ hashCode contracts were incorrectly implemented. I'm thinking whether the client-side part of the grid component isn't somehow faulty.

TatuLund commented 2 years ago

As a next step I would recommend to strip the Lombok away from your test app and in general simplify it. I.e. reduce other possible sources of error. If the issue still replicates, there are less options to be studied and debugged.

Leaghte commented 2 years ago

I stripped the Lombok away from the project and the issue is unfortunately still present.

TatuLund commented 2 years ago

I noticed that your demo app is using this add-on https://vaadin.com/directory/component/spring-data-provider-add-on

Have you tried to simplify the logic to use normal DataProvider from the call backs instead of this add-on?

TatuLund commented 2 years ago

I finally had time to download your app and play with. I am quite convinced that the problem is not in Grid at all, but in Spring Data Provider add-on. There is also vague bug report there, that could be related.

https://github.com/Artur-/spring-data-provider/issues/11

I noticed that I can replicate the problem when I sort based on user name. The duplicates disappear when I change the sort back to be based on id. So clearly the data provider does not use Grid's sorting properly when fetching the data.

SebastianDietrich commented 1 year ago

AFAICS (didn't test my assumption) Java-Faker might return duplicates - i.e. users that have the same firstName or lastName or username. So when you sort by e.g. username (as in the video), you might get duplicate entries (in the sense of entries that are on the same "position" when sorted). Pagination does not work well with that, so in VaadinView you should add columns by providing their sortProperty including somithing that makes it unique (e.g. ID): e.g.

grid.addColumn(User::getUsername)
    .setId("username")
    .setSortProperty("username", "id").
    .setCaption("Username");