com.vaadin.ui.Grid may not reliably update items on a lazy Container

Hi guys,

first of all congratulations for delivering 7.4 and thanks for the new Grid.

I have however to point out a strange behavior that I’ve been observing, as a developer of a
lazy

Container
implementation (the

Lazy MongoDBContainer

) and a user and contributor to the
Viritin Add-on
. The new Grid widget seems to rely on
listeners
on the properties of
Items
in order to decide whether an Item in the Grid should be
updated
when it has been
edited
. This is perfectly legitimate, but the caveat, is that the
listeners
might be installed on a property of
the wrong item instance.

The problem seems to originate from the contract of the
Container.getItem(id)
API. The JavaDoc states:

but, apparently, a
stronger assumption
is made in the code of the
Grid
; that is, for one given
itemId
the
instance
of the Item object that is returned by a Container is supposed to be always the
same
. In other words, suppose that
itemId
is an Item id; then, it is assumed that the condition
getItem(itemId) == getItem(itemId)

always
holds.

The grid invokes the
getItem(itemId)
at least
once
, when the Item is being displayed. When you begin an editing session (either by double-clicking, or programmatically, through the
editItem(itemId)
API) Grid invokes
getItem(itemId)

again
, and the returned Item instance is set as the data source of the FieldGroup instance that is used for displaying the inline-editing fields;
listeners
are installed on the properties of
this
Item.

In
Viritin’s ListContainer
and in the
MongoContainer,
Items are generated
lazily
upon request. This is by design, because the number of elements that these containers expose to Vaadin might be well over the thousands (in Mongo, possibly hundreds of thousands). Therefore, it is unfeasible to keep track of
all
the Item instances that might be generated.

Consequently, when the Grid edit mode is left, events are fired, but the Grid is not updated, because the Item instance that is being displayed is not the same that was edited! You can also see that the problem would occur even if we were not using the inline editing feature, because each
Container.getItem(id)
invocation
is not guaranteed
(by design) to always return the same Item instance!

The Table gave us a convenient
refreshRowCache()
mechanism to force reloading, but, there is no equivalent in Grid. A workaround that
I am currently investigating with Matti
is to put a simple caching mechanism in front of a lazy container implementation.

However, I feel like it would be more reliable for the Grid to
reload the Item automatically
when the
save
button is clicked (that is, when
editorSave()
is invoked,
and/or
to
provide
APIs to do this upon request, similarly to the Table.
e.g.,

refreshItem(itemId)
or
refreshPage()
.

What to do you guys think?

User
ares242
of the MongoContainer
suggests the following workaround
:

java.lang.reflect.Field f = grid.getClass().getDeclaredField("datasourceExtension"); f.setAccessible(true); RpcDataProviderExtension rpc = (RpcDataProviderExtension) f.get(grid); rpc.updateRowData(obj.getId()); Although I would not advise using reflection for this, I would suggest to expose this
updateRowData()
method to the public API. In the meantime a less-hacky hack is using:

grid.setCellStyleGenerator(grid.getCellStyleGenerator()); which relies on the (undocumented) side effect that
setCellStyleGenerator()
invokes
datasourceExtension.refreshCache()

The advantage of my aproach using reflection, despite being awkward, is that only updates the given row and no all the grid.


Related ticket.