vaadin / framework

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

Vaadin 8.1.0 rc1 + Grid problem #9678

Closed skoude closed 5 years ago

skoude commented 7 years ago

Hi!

I'm moving from Java and Vaadin 7.7 to vaadin-on-kotlin framework that uses vaadin 8.1.0.rc1.

The problem that I have is not a vaadin-on-kotlin specific, but it's more specific to Grid component and editing values there..

The problem is that when I open the view, it lists all the rows correctly with correct data. Filters and sorting also works perfectly. But when I try to edit anything, I get the exception:

10:03:03.833 [qtp279680875-909] ERROR c.vaadin.server.DefaultErrorHandler -
java.lang.IllegalStateException: Duplicate key Person(firstName=matti222, lastName=meikalainen22, sotu=111111)
at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
at java.util.HashMap.merge(HashMap.java:1245)
at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1540)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at com.vaadin.data.provider.DataCommunicator$ActiveDataHandler.getActiveData(DataCommunicator.java:165)
at com.vaadin.data.provider.DataCommunicator.refresh(DataCommunicator.java:521)
at com.vaadin.ui.AbstractListing$AbstractListingExtension.refresh(AbstractListing.java:122)
at com.vaadin.ui.components.grid.EditorImpl.save(EditorImpl.java:250)
at com.vaadin.ui.components.grid.EditorImpl$1.save(EditorImpl.java:133)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:155)
at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:116)
at com.vaadin.server.communication.ServerRpcHandler.handleInvocation(ServerRpcHandler.java:445)
at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:410)
at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:274)
at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:90)
at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:41)
at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1577)
at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:381)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:812)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669)
at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:224)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:499)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:745)

and here is the code(written in kotlin), that I'm using:

@AutoView("")
class TestView: VerticalLayout(), View {

    private lateinit  var personGrid: Grid<Person>
    private lateinit  var firstNameFilter: TextField
    var persons = listOf<Person>(Person(1, "matti", "meikalainen", "111111"), Person(2, "teppo", "testaajaa", "2222222"))

    companion object {
        fun navigateTo() = navigateToView<WelcomeView>()
    }

    init {

        var personsListProvider = ListDataProvider<Person>(persons).withConfigurableFilter()

        isMargin = false
        label("Vaadin On Kotlin testview") {
            w = fillParent
            addStyleNames(ValoTheme.LABEL_H1, ValoTheme.LABEL_COLORED)
        }

        personGrid = grid(Person::class, "List of Persons", personsListProvider) {
            setItems(persons)
            expandRatio = 1f;
            setSizeFull()

            val binder: Binder<Person> = getEditor().getBinder()

            column(Person::firstName) {
                caption="firstname"
                setEditorComponent(TextField("firstname"), Person::firstName.setter)
               isEditable = true
                isHidden = false
            }

            column(Person::lastName) {
                setEditorComponent(TextField("lastname"), Person::lastName.setter)
                isEditable = true
            }

            column(Person::sotu) {
                setEditorComponent(TextField("sotu"), Person::sotu.setter)
                isEditable = true

            }

            editor.addCancelListener( { event -> Notification.show("Editing Cancelled...")
            } )
            editor.addSaveListener({ event ->
                Notification.show("Saving ${event.bean.firstName} - ${event.bean.lastName} - ${event.bean.sotu} -...")
                binder.writeBean(event.bean)

                //personsListProvider.refreshAll()

                // just for debugging to see what's in the provider now..
                /*personsListProvider.getAll().forEach(
                        {
                            println("${it.firstName} - ${it.lastName} - ${it.sotu}")
                        }
                )*/

                refresh()

            })

            editor.setSaveCaption("Tallenna")
            editor.setCancelCaption("Peruuta")

            editor.setEnabled(true)

            addColumn({ "Show" }, ButtonRenderer<Person>({ event -> personGrid.refresh() }))
            addColumn({ "Edit" }, ButtonRenderer<Person>({ event -> null }))
            addColumn({ "Delete" }, ButtonRenderer<Person>({ event -> null }))

            // automatically create filters, based on the types of values present in particular columns.
            appendHeaderRow().generateFilterComponents(this, Person::class)

        }

        personGrid.addItemClickListener({ event -> Notification.show("Value: " + event.getItem()) })

    }

    override fun enter(event: ViewChangeListener.ViewChangeEvent?) {
        personGrid.dataProvider.refreshAll()
    }

}

Here is more discussion about this: vaadin-on-kotlin issue 6

SteveDemy commented 7 years ago

Same issue here. It manifests intermittently when a Grid 8 cell is edited and the save button is pushed. Many times the save function works as expected. The database has no duplicated keys in it and the Grid otherwise functions correctly. Environment:

java version 1.8.0_141 Tomcat 8.5.19 Vaadin 8.1.0

Aug 01, 2017 5:30:36 PM com.vaadin.server.DefaultErrorHandler doDefault
SEVERE: 
java.lang.IllegalStateException: Duplicate key {doneat=5749.6, log4=0, log5=1, worktype=Inspection, description=Phase C / 50hr On-condition inspection, workdone=Tightened fuel cap, doneon=2017-05-30 16:43:29.0, workordernumber=14, planeid=1377035000007, log2=0, complete=1, log3=1, maintid=1495120791323, log1=1}
    at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
    at java.util.HashMap.merge(HashMap.java:1253)
    at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
    at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
    at java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1548)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
    at com.vaadin.data.provider.DataCommunicator$ActiveDataHandler.getActiveData(DataCommunicator.java:165)
    at com.vaadin.data.provider.DataCommunicator.refresh(DataCommunicator.java:521)
    at com.vaadin.ui.AbstractListing$AbstractListingExtension.refresh(AbstractListing.java:122)
    at com.vaadin.ui.components.grid.EditorImpl.save(EditorImpl.java:250)
    at com.vaadin.ui.components.grid.EditorImpl$1.save(EditorImpl.java:133)
    at sun.reflect.GeneratedMethodAccessor39.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:155)
    at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:116)
    at com.vaadin.server.communication.ServerRpcHandler.handleInvocation(ServerRpcHandler.java:445)
    at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:410)
    at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:274)
    at com.vaadin.server.communication.PushHandler.lambda$new$1(PushHandler.java:145)
    at com.vaadin.server.communication.PushHandler.callWithUi(PushHandler.java:235)
    at com.vaadin.server.communication.PushHandler.onMessage(PushHandler.java:520)
    at com.vaadin.server.communication.PushAtmosphereHandler.onMessage(PushAtmosphereHandler.java:87)
    at com.vaadin.server.communication.PushAtmosphereHandler.onRequest(PushAtmosphereHandler.java:77)
    at org.atmosphere.cpr.AsynchronousProcessor.action(AsynchronousProcessor.java:223)
    at org.atmosphere.cpr.AsynchronousProcessor.suspended(AsynchronousProcessor.java:115)
    at org.atmosphere.container.Servlet30CometSupport.service(Servlet30CometSupport.java:67)
    at org.atmosphere.cpr.AtmosphereFramework.doCometSupport(AtmosphereFramework.java:2284)
    at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.java:593)
    at org.atmosphere.websocket.DefaultWebSocketProcessor$3.run(DefaultWebSocketProcessor.java:345)
    at org.atmosphere.util.VoidExecutorService.execute(VoidExecutorService.java:101)
    at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.java:340)
    at org.atmosphere.websocket.DefaultWebSocketProcessor.invokeWebSocketProtocol(DefaultWebSocketProcessor.java:447)
    at org.atmosphere.container.JSR356Endpoint$3.onMessage(JSR356Endpoint.java:272)
    at org.atmosphere.container.JSR356Endpoint$3.onMessage(JSR356Endpoint.java:269)
    at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:395)
    at org.apache.tomcat.websocket.server.WsFrameServer.sendMessageText(WsFrameServer.java:119)
    at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:495)
    at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:294)
    at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:133)
    at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:82)
    at org.apache.tomcat.websocket.server.WsFrameServer.doOnDataAvailable(WsFrameServer.java:171)
    at org.apache.tomcat.websocket.server.WsFrameServer.notifyDataAvailable(WsFrameServer.java:151)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:148)
    at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
m-bermel commented 7 years ago

We were also having trouble with this problem. As far as I could debug it, there seems to be a problem how the DataProvider handles the internal mapping in the DataCommunicator with the KeyMapper. Or we're just using it wrong ;)

After adding new objects to the ListDataProvider, saving these and reloading them the internal mapping is thrown off. Let's say I saved 10 objects, the keyObjectMap HashMap in the KeyMapper would have 16 objects now of which 6 are duplicates. But my backend only delivers 10 objects

backend.saveData(listDataProvider.getItems());
listDataProvider.getItems().clear();
listDataProvider.getItems().addAll(backend.getData());

We solved the problem by creating a new ListDataProvider each time we need to reload the data from the backend. Not the best solution in relation to memory usage but at least it works now.

backend.saveData(listDataProvider.getItems());
listDataProvider = DataProvider.ofCollection(backend.getData());
grid.setDataProvider(listDataProvider );
listDataProvider.refreshAll();
maticpetek commented 7 years ago

We have the some problem - we are using version 8.1.5. m-bermel solution has not work for use. We are still getting an exception.

m-bermel commented 7 years ago

We also sometime still run into this kinda exception. With the code changes I wrote the error occurs less often ... but that's not really a solution...

@maticpetek do you work with switching the SelectionMode from SINGLE to MULTI and vice versa?

metakocka commented 7 years ago

@m-bermel I try with MULTI and it helps the first 10 minuts. But then I again get the some exception. Now I gave up with Editor Grid - i would implement form as list - detail.

pleku commented 7 years ago

Hello. Have you overridden the getId method for the DataProvider ? Could you mayhaps try that and see if the issue still reproduces ? Thanks

AntonKtrue commented 6 years ago

Try to override hash code in the POJO: don't use fields what can be changed in vaadin UI to generate hashcode. It help for me =)

dmmax commented 6 years ago

I had same problem. This situation occurred after connection lombok to my project and annotated DTO class with @Data. This annotation automatically generate hashCode method with all properties.

I added additional annotation @EqualsAndHashCode(of = "id") argument 'of' contains fields that are to be used for identity.

draedel commented 6 years ago

Same problem here.

Workaround: Completely remove the equals() and hashCode() methods in the POJO. In my case (Vaadin 8.3.0), this was the best solution as I don't really need these methods.

Adding an additional dummy value to the hashcode would have rendered this method useless, anyway. And only using fields in the hashcode that can't be changed in the UI was no option as these fields needed to be changed. Setting a new DataProvider was also no option as this made problems with my filter.

stale[bot] commented 6 years ago

Hello there!

It looks like this issue hasn't progressed lately. There are so many issues that we just can't deal them all within a reasonable timeframe.

There are a couple of things you could help to get things rolling on this issue (this is an automated message, so expect that some of these are already in use):

Thanks again for your contributions! Even though we haven't been able to get this issue fixed, we hope you to report your findings and enhancement ideas in the future too!

fleahy commented 6 years ago

I'm still getting the same issue in the latest version of Vaadin 8, 8.5.2. It seems that there's something wrong with my code but I can't figure out what exactly it is so I can fix it. Still working on it...

ldelaprade commented 5 years ago

We were also having trouble with this problem. As far as I could debug it, there seems to be a problem how the DataProvider handles the internal mapping in the DataCommunicator with the KeyMapper. Or we're just using it wrong ;)

After adding new objects to the ListDataProvider, saving these and reloading them the internal mapping is thrown off. Let's say I saved 10 objects, the keyObjectMap HashMap in the KeyMapper would have 16 objects now of which 6 are duplicates. But my backend only delivers 10 objects

backend.saveData(listDataProvider.getItems());
listDataProvider.getItems().clear();
listDataProvider.getItems().addAll(backend.getData());

We solved the problem by creating a new ListDataProvider each time we need to reload the data from the backend. Not the best solution in relation to memory usage but at least it works now.

backend.saveData(listDataProvider.getItems());
listDataProvider = DataProvider.ofCollection(backend.getData());
grid.setDataProvider(listDataProvider );
listDataProvider.refreshAll();

Same issue with Vaadin 8.4.5 grid (cannot go beyoud this version yet because my project still contain vaadin 7 components). Also solved with workaround related to data provider, however, I didn't have to recreate a new data provider each time - it was enough to reassign the same one to the grid. i.e. each time my backend list change, calling grid.setDataProvider(listDataProvider ) eventually solved the DUP issue exceptions... :-)

stale[bot] commented 5 years ago

Hello there!

We are sorry that this issue hasn't progressed lately. We are prioritizing issues by severity and the number of customers we expect are experiencing this and haven't gotten around to fix this issue yet.

There are a couple of things you could help to get things rolling on this issue (this is an automated message, so expect that some of these are already in use):

Thanks again for your contributions! Even though we haven't been able to get this issue fixed, we hope you to report your findings and enhancement ideas in the future too!