ConcurrentModificationException when using Tokenlist

Hi,

Recently we have found some issue when using the Tokenlist in combination with the refreshOptionsOnLookupClose attribute (set to true). Whenever we do so, we get a ConcurrentModificationException after selecting a third item from the available list of items, like this:

  • open an editor with a tokenlist as defined below and have a list of 3+ available items
  • add two items using the dropdown selector, this does not cause any problem
  • add a third item and the exception occurs

If we remove the refreshOptionsOnLookupClose attribute, everything works fine but the dropdown list will not refresh if we alter it during editing (using the lookup action).

Tokenlist definition:

       <tokenList datasource="selectedDataDs"
                  clearEnabled="false"
                  refreshOptionsOnLookupClose="true"
                  inline="true"
                  width="100%">
           <lookup lookup="true"
                   optionsDatasource="allDatasDs"/>
       </tokenList>

The exception log:

09:06:24.209 ERROR com.haulmont.cuba.web.log.AppLog        - Exception in com.haulmont.cuba.web.widgets.CubaComboBox: 
com.vaadin.server.ServerRpcManager$RpcInvocationException: Unable to invoke method select in com.vaadin.shared.data.selection.SelectionServerRpc
	at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:157) ~[vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:115) ~[vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	at com.vaadin.server.communication.ServerRpcHandler.handleInvocation(ServerRpcHandler.java:431) [vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:396) [vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:260) [vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:82) [vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40) [vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1577) [vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:425) [vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	at com.haulmont.cuba.web.sys.CubaApplicationServlet.serviceAppRequest(CubaApplicationServlet.java:329) [cuba-web-7.1.8.jar:7.1.8]
	at com.haulmont.cuba.web.sys.CubaApplicationServlet.service(CubaApplicationServlet.java:215) [cuba-web-7.1.8.jar:7.1.8]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) [servlet-api.jar:na]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [catalina.jar:9.0.14]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:9.0.14]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) [tomcat-websocket.jar:9.0.14]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:9.0.14]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:9.0.14]
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:108) [spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at com.haulmont.addon.saml.web.security.saml.SamlLoginHttpRequestFilter.doFilter(SamlLoginHttpRequestFilter.java:110) [saml-addon-web-0.3.1.jar:na]
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113) [spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74) [spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE]
	at com.haulmont.cuba.web.sys.CubaHttpFilter.doFilter(CubaHttpFilter.java:93) [cuba-web-7.1.8.jar:7.1.8]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:9.0.14]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:9.0.14]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) [catalina.jar:9.0.14]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [catalina.jar:9.0.14]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) [catalina.jar:9.0.14]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [catalina.jar:9.0.14]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [catalina.jar:9.0.14]
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:668) [catalina.jar:9.0.14]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [catalina.jar:9.0.14]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [catalina.jar:9.0.14]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) [tomcat-coyote.jar:9.0.14]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-coyote.jar:9.0.14]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) [tomcat-coyote.jar:9.0.14]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417) [tomcat-coyote.jar:9.0.14]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-coyote.jar:9.0.14]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_221]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_221]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-util.jar:9.0.14]
	at java.lang.Thread.run(Thread.java:748) [na:1.8.0_221]
Caused by: java.lang.reflect.InvocationTargetException: null
	at sun.reflect.GeneratedMethodAccessor474.invoke(Unknown Source) ~[na:na]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_221]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_221]
	at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:153) ~[vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	... 40 common frames omitted
Caused by: com.vaadin.event.ListenerMethod$MethodException: Invocation of method selectionChange in com.vaadin.ui.ComboBox$$Lambda$2543/1001670089 failed.
	at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:516) ~[vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:273) ~[vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:237) ~[vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:1041) ~[vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	at com.vaadin.ui.AbstractSingleSelect.setSelectedItem(AbstractSingleSelect.java:358) ~[vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	at com.vaadin.ui.AbstractSingleSelect$1.select(AbstractSingleSelect.java:291) ~[vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	... 44 common frames omitted
Caused by: java.util.ConcurrentModificationException: null
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909) ~[na:1.8.0_221]
	at java.util.ArrayList$Itr.next(ArrayList.java:859) ~[na:1.8.0_221]
	at com.haulmont.cuba.web.gui.components.WebTokenList.refreshValueIfNeeded(WebTokenList.java:499) ~[cuba-web-7.1.8.jar:7.1.8]
	at com.haulmont.cuba.web.gui.components.WebTokenList.handleSelection(WebTokenList.java:467) ~[cuba-web-7.1.8.jar:7.1.8]
	at com.haulmont.cuba.web.gui.components.WebTokenList.addValueFromLookupPickerField(WebTokenList.java:752) ~[cuba-web-7.1.8.jar:7.1.8]
	at com.haulmont.cuba.web.gui.components.WebTokenList.lambda$new$0(WebTokenList.java:92) ~[cuba-web-7.1.8.jar:7.1.8]
	at com.haulmont.bali.events.EventHub.publish(EventHub.java:170) ~[cuba-global-7.1.8.jar:7.1.8]
	at com.haulmont.cuba.web.gui.components.WebAbstractComponent.publish(WebAbstractComponent.java:92) ~[cuba-web-7.1.8.jar:7.1.8]
	at com.haulmont.cuba.web.gui.components.WebAbstractValueComponent.componentValueChanged(WebAbstractValueComponent.java:152) ~[cuba-web-7.1.8.jar:7.1.8]
	at com.haulmont.cuba.web.gui.components.WebV8AbstractField.lambda$attachValueChangeListener$ab1c93c8$1(WebV8AbstractField.java:144) ~[cuba-web-7.1.8.jar:7.1.8]
	at com.vaadin.ui.ComboBox.lambda$addValueChangeListener$bddd7469$1(ComboBox.java:807) ~[vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	at sun.reflect.GeneratedMethodAccessor469.invoke(Unknown Source) ~[na:na]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_221]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_221]
	at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:496) ~[vaadin-server-8.6.4-30-cuba.jar:8.6.4-30-cuba]
	... 49 common frames omitted

We have verified this behavior in 6.x and 7.x using both legacy screens and the 7.x screen definitions. Even with editors generated by the studio (and then altered to use the tokenlist) as shown above. The behavior is consistent in all cases.

There is no other code involved.

Is this an issue or is it undefined behavior? We actually couldn’t find documentation of the refreshOptionsOnLookupClose attribute.

Thanks for any help on this.

Regards,
-b

Hello @b.tel,

Yes, it is a bug. I’ve created an issue: cuba-platform/cuba#3112, thank you for the reporting the problem!

refreshOptionsOnLookupClose - reloads options in the TokenList

You can disable this property and refresh options manually:

@Inject
private TokenList<OrderLine> tokenList;

@Subscribe("tokenList")
public void onTokenListValueChange(HasValue.ValueChangeEvent<Collection<OrderLine>> event) {
    EntityOptions<OrderLine> entityOptions = (EntityOptions<OrderLine>) tokenList.getOptions();
    entityOptions.refresh();

    if (event.getValue() == null) {
        return;
    }
    
    for (OrderLine ol : event.getValue()) {
        // update order link due to refresh() may remove it
        if (ol.getOrder() == null) {
            ol.setOrder(getEditedEntity());
        }
    }
}

Hi,

Ok, glad to hear it’s a bug and you will fix it. We have many tokenlists in our application and adding this code will be a major piece of work while being a temporary solution. I guess we will wait for the bug fix and meanwhile disable the refresh.

Thanks for your quick reply!
-b