Error after deleting Grid row(s)

Using Grid with an SQLContainer data source, in multi-select mode.

Delete one or more items from the container, the corresponding Grid’s rows are removed as expected. But all subsequent row selections or de-selections result in this error. The item being referenced in the error is the one that was deleted. The problem is not present in single select mode.

Mar 09, 2015 5:31:58 PM com.vaadin.server.DefaultErrorHandler doDefault
SEVERE: 
java.lang.IllegalArgumentException: Given item id (vfc_C172/1425759773838) does not exist in the container
    at com.vaadin.ui.Grid$AbstractSelectionModel.checkItemIdExists(Grid.java:731)
    at com.vaadin.ui.Grid$AbstractSelectionModel.checkItemIdsExist(Grid.java:749)
    at com.vaadin.ui.Grid$MultiSelectionModel.setSelected(Grid.java:1064)
    at com.vaadin.ui.Grid$3.select(Grid.java:3005)
    at sun.reflect.GeneratedMethodAccessor29.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:168)
    at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:118)
    at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:291)
    at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:184)
    at com.vaadin.server.communication.PushHandler$3.run(PushHandler.java:176)
    at com.vaadin.server.communication.PushHandler.callWithUi(PushHandler.java:255)
    at com.vaadin.server.communication.PushHandler.access$200(PushHandler.java:58)
    at com.vaadin.server.communication.PushHandler$1.onRequest(PushHandler.java:78)
    at org.atmosphere.cpr.AsynchronousProcessor.action(AsynchronousProcessor.java:205)
    at org.atmosphere.cpr.AsynchronousProcessor.suspended(AsynchronousProcessor.java:104)
    at org.atmosphere.container.Servlet30CometSupport.service(Servlet30CometSupport.java:66)
    at org.atmosphere.cpr.AtmosphereFramework.doCometSupport(AtmosphereFramework.java:2075)
    at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.java:570)
    at org.atmosphere.websocket.DefaultWebSocketProcessor$3.run(DefaultWebSocketProcessor.java:332)
    at org.atmosphere.util.VoidExecutorService.execute(VoidExecutorService.java:101)
    at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.java:327)
    at org.atmosphere.websocket.DefaultWebSocketProcessor.invokeWebSocketProtocol(DefaultWebSocketProcessor.java:424)
    at org.atmosphere.container.JSR356Endpoint$1.onMessage(JSR356Endpoint.java:206)
    at org.atmosphere.container.JSR356Endpoint$1.onMessage(JSR356Endpoint.java:203)
    at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:393)
    at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:494)
    at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:289)
    at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:130)
    at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:60)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:203)
    at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:198)
    at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:96)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:654)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1558)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1515)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

Vaadin 7.4.1, Tomcat 8.0.20,

This looks a lot like the problem in
#16195
, which is still under work.

Johannes suggests a workaround there: “A workaround is to deselect removed items manually.”

It seems to help:

[code]
// Allow deleting the selected items
Button deleteSelected = new Button(“Delete Selected”, e → {
// TODO A workaround for #16195
List toDelete = new ArrayList();
for (Object itemId: grid.getSelectedRows()) {
toDelete.add(itemId);
grid.deselect(itemId); // Must deselect manually
}

// Delete all selected data items
for (Object itemId: toDelete)
    grid.getContainerDataSource().removeItem(itemId);

});
[/code] Perhaps you can do the deselection in the same loop as the removal, I’m just playing safe there. However, I’m still getting some random IllegalStateExceptions about missing items occasionally. That could be a separate problem.

Thanks very much Marko. I missed #16195 and see now that Johannes is on it.

Is it safe to deselect(itemID) which changes the getSelectedRows collection while referring to that collection in the loop? Maybe it is, but this avoids any doubt and appears to work so far.

            final Collection<Object> itemIDsToBeRemoved = getSelectedRows();
                for ( Object itemID: itemIDsToBeRemoved ) {
                    deselect(itemID);
                    standbyContainer.removeItem(itemID);
                }

I think it’s safe, as it looks like getSelectedRows() makes a copy of the selected items collection.

Therefore, you don’t need the variable there, but can just use for ( Object itemID: getSelectedRows()).

Moreover, it looks like the problem occurs next time the user changes the selection, so it should be perfectly fine to remove the selection
after
you remove the items from the container. Therefore, you could simply use the reset() on the selection model, which with multi-select empties the selection.

Button deleteSelected = new Button("Delete Selected", e -> {
    // Delete all selected data items
    for (Object itemId: grid.getSelectedRows())
        grid.getContainerDataSource().removeItem(itemId);

    // TODO A workaround for #16195
    grid.getSelectionModel().reset();
});

Hi,

Unfortunately the ticket (and a patch I wrote) has been left hanging due to design issues - in general it is very hard to efficiently ensure the selection is always in sync with the container contents. In AbstractSelect-based components (Table, ComboBox etc) the same issue was resolved by adding a “sanitizeSelection” method that can be manually invoked when needed. Those components do not suffer from the much more serious issue of actually throwing exceptions when the desync happens, and this problem should be fixed in Grid as soon as possible.

I just ran into this issue myself (using the default data source) and ended up here after searching for a solution. I wanted to mention as an FYI that the getSelectionModel().reset() workaround is working fine for me.

I used the ‘deselect’ workaround mentioned in #16195 which worked fine for me. Another issue occurs with multiselect and filters: add a filter to your grid, select a row, change the filter (first selected item not included in the result), and select another one…

java.lang.IllegalArgumentException: Given item id (7) does not exist in the container
    at com.vaadin.ui.Grid$AbstractSelectionModel.checkItemIdExists(Grid.java:908)
    at com.vaadin.ui.Grid$AbstractSelectionModel.checkItemIdsExist(Grid.java:926)
    at com.vaadin.ui.Grid$MultiSelectionModel.setSelected(Grid.java:1249)
    at com.vaadin.ui.Grid$3.select(Grid.java:3706)