简体   繁体   English

cloneEntity上的java.util.ConcurrentModificationException

[英]java.util.ConcurrentModificationException on cloneEntity

I wrote a custom strategy in order to clone an entity TrainTimetable with its collection of slots . 我编写了一个自定义策略,以克隆带有其slots集合的实体TrainTimetable

Below an extract of the model : 下面是该模型的摘录:

Entity('TrainTimetable') {
    list        'slots'             , ref:'Slot', composition:true
}
Entity('Slot') {
    reference   'trainTimetable'    , ref:'TrainTimetable', reverse:'TrainTimetable-slots'
}

And below the method : 和下面的方法:

package fr.yc.rail.backend;

import java.util.ArrayList;
import java.util.List;

import org.jspresso.framework.model.entity.IEntity;
import org.jspresso.framework.model.entity.IEntityFactory;
import org.jspresso.framework.model.entity.SmartEntityCloneFactory;

import fr.yc.rail.model.Slot;
import fr.yc.rail.model.TrainTimetable;

public class CloneTrainTimetableFactory extends SmartEntityCloneFactory {

    @Override
    public <E extends IEntity> E cloneEntity(E entityToClone,
            IEntityFactory entityFactory) {

        TrainTimetable clonedTrainTimetable = (TrainTimetable) super.cloneEntity(entityToClone, entityFactory);

        TrainTimetable trainTimetableToClone = (TrainTimetable) entityToClone;

        List<Slot> clonedSlots = new ArrayList<Slot>();

        trainTimetableToClone.getSlots().each {
            Slot clonedSlot = super.cloneEntity(it, entityFactory);
            clonedSlots.add(clonedSlot);
        }

        clonedTrainTimetable.setSlots(clonedSlots);

        return (E) clonedTrainTimetable;
    }
}

When the method is called, the code below raises the ConcurrentModificationException error on the second iteration : 调用该方法时,以下代码在第二次迭代时引发ConcurrentModificationException错误:

trainTimetableToClone.getSlots().each {
    Slot clonedSlot = super.cloneEntity(it, entityFactory);
    clonedSlots.add(clonedSlot);
}

Below the stack trace : 在堆栈跟踪下面:

ERROR <2015-06-09 18:13:11,193> org.jspresso.framework.application.frontend.controller.AbstractFrontendController : An unexpected error occurred for user demo on session 4379dc1b.
java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at org.hibernate.collection.internal.AbstractPersistentCollection$IteratorProxy.next(AbstractPersistentCollection.java:774)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1378)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1372)
    at org.codehaus.groovy.runtime.dgm$149.invoke(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:271)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:53)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at fr.yc.rail.backend.CloneTrainTimetableFactory.cloneEntity(CloneTrainTimetableFactory.groovy:25)
    at org.jspresso.framework.application.backend.action.CloneComponentCollectionAction.cloneElement(CloneComponentCollectionAction.java:61)
    at org.jspresso.framework.application.backend.action.AbstractCloneCollectionAction.getAddedComponents(AbstractCloneCollectionAction.java:71)
    at org.jspresso.framework.application.backend.action.AbstractAddCollectionToMasterAction.execute(AbstractAddCollectionToMasterAction.java:78)
    at org.jspresso.framework.application.backend.AbstractBackendController.execute(AbstractBackendController.java:403)
    at org.jspresso.framework.application.frontend.controller.AbstractFrontendController.executeBackend(AbstractFrontendController.java:1536)
    at org.jspresso.framework.application.frontend.controller.AbstractFrontendController.execute(AbstractFrontendController.java:576)
    at org.jspresso.framework.application.action.AbstractAction.execute(AbstractAction.java:114)
    at org.jspresso.framework.application.frontend.controller.AbstractFrontendController.executeFrontend(AbstractFrontendController.java:1549)
    at org.jspresso.framework.application.frontend.controller.AbstractFrontendController.execute(AbstractFrontendController.java:578)
    at org.jspresso.framework.view.remote.RemoteActionFactory$ActionAdapter.actionPerformed(RemoteActionFactory.java:235)
    at org.jspresso.framework.application.frontend.controller.remote.AbstractRemoteController.handleCommand(AbstractRemoteController.java:440)
    at org.jspresso.framework.application.frontend.controller.remote.AbstractRemoteController.handleCommands(AbstractRemoteController.java:202)
    at org.jspresso.framework.application.startup.remote.RemoteStartup.handleCommands(RemoteStartup.java:88)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at net.sf.qooxdoo.rpc.RemoteCallUtils.callCompatibleMethod(RemoteCallUtils.java:469)
    at net.sf.qooxdoo.rpc.RpcServlet.handleRPC(RpcServlet.java:374)
    at net.sf.qooxdoo.rpc.RpcServlet.doPost(RpcServlet.java:481)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.jspresso.framework.util.http.HttpRequestHolder.doFilter(HttpRequestHolder.java:99)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)

The error means that I am iterating on a collection that is changing in size, but I don't know how to get rid of it. 该错误意味着我正在迭代一个大小不断变化的集合,但是我不知道如何摆脱它。

You have a 1-N bi-directional association between TrainTimetable and Slot . 您在TrainTimetableSlot之间具有1-N双向关联。 This means that whenever you update one side of the association, Jspresso will take care of updating the other side in order to keep model consistency, eg : 这意味着每当您更新关联的一侧时,Jspresso都会负责更新另一侧,以保持模型的一致性,例如:

  • if you set the trainTimetable property on a slot, the slot will be added to the reverse slots collection of the train timetable. 如果在插槽上设置trainTimetable属性,则该插槽将被添加到火车时间表的反向slots集合中。
  • if you add a slot to the slots property of a train timetable, then the trainTimetable reverse property of the added slot will be updated to the train timetable. 如果添加了一个槽的slots列车时刻表的属性,则trainTimetable反向增加槽的属性将被更新到列车时刻表。

In the following code : 在下面的代码中:

 Slot clonedSlot = super.cloneEntity(it, entityFactory);

the clonedSlot will be added to the trainTimeTableToClone slots due to the rules explained before. 由于之前说明的规则, clonedSlot将添加到trainTimeTableToClone插槽。 So the iterated collection actually changes. 因此,迭代的集合实际上发生了变化。

In order to fix the problem, making a copy of the collection before iterating it should be enough, ie : 为了解决该问题,在迭代之前制作一个集合的副本就足够了,即:

trainTimetableToClone.getSlots().collect().each {

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM