我正在开发一个Tree组件,可能会根据用户输入进行修剪。我将所有节点都缓存,以便为primefaces组件模型提供始终与树节点相同的实例。
但问题是,当我更改父子关系(删除其中一些)时,我总是得到一个并发修改异常...有没有办法解决这个问题或者我错过了什么。
提前致谢。
/**
* Recursively copy the hierarchy and prune not visible branches
* @param originalNode node of the original hierarchy to be copied
* @param parent parent node in the new hierarchy
* @param visibleNodes set of nodes, which should be included in the new hierarchy
* @param model model of the TreeAutompleteComponent
* @return copy of the oroginal node in the new hierarchy
*/
private TreeNode copyHierarchy(TreeNode originalNode, TreeNode parent, Set<TreeNode> visibleNodes, TreeAutocompleteModel model) {
if (!visibleNodes.contains(originalNode)) {
return null;
}
TreeNode newNode = model.getCompleteModelNodes().get(((NodeWrapper)originalNode.getData()).getIri());//new DefaultTreeNode(originalNode.getData(), parent);
for (int i = 0; i < originalNode.getChildCount(); i++) {
copyHierarchy((TreeNode) originalNode.getChildren().get(i), newNode, visibleNodes, model);
}
newNode.setParent(parent); //when removed, no exception occurs
return newNode;
}
例外
ava.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
at org.primefaces.component.tree.TreeRenderer.encodeTreeNodeChildren(TreeRenderer.java:284)
at org.primefaces.component.tree.TreeRenderer.encodeTreeNode(TreeRenderer.java:274)
at org.primefaces.component.tree.TreeRenderer.encodeMarkup(TreeRenderer.java:165)
at org.primefaces.component.tree.TreeRenderer.encodeEnd(TreeRenderer.java:96)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:875)
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:312)
at com.sun.faces.renderkit.html_basic.GroupRenderer.encodeChildren(GroupRenderer.java:105)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:304)
at com.sun.faces.renderkit.html_basic.GridRenderer.renderRow(GridRenderer.java:185)
at com.sun.faces.renderkit.html_basic.GridRenderer.encodeChildren(GridRenderer.java:129)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:304)
at com.sun.faces.renderkit.html_basic.GridRenderer.renderRow(GridRenderer.java:185)
at com.sun.faces.renderkit.html_basic.GridRenderer.encodeChildren(GridRenderer.java:129)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:304)
at com.sun.faces.renderkit.html_basic.GroupRenderer.encodeChildren(GroupRenderer.java:105)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:304)
at com.sun.faces.renderkit.html_basic.GroupRenderer.encodeChildren(GroupRenderer.java:105)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:304)
at com.sun.faces.renderkit.html_basic.GroupRenderer.encodeChildren(GroupRenderer.java:105)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1779)
at com.sun.faces.renderkit.html_basic.CompositeRenderer.encodeChildren(CompositeRenderer.java:78)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1779)
at javax.faces.render.Renderer.encodeChildren(Renderer.java:168)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1779)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1782)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1782)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:424)
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:125)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:563)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:399)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:317)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:204)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:182)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:311)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
答案 0 :(得分:2)
您正在尝试修改当前正在迭代的集合。
您是否尝试过处理相关集合的副本而不是修改当前集合?
来自http://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html:
请注意,此异常并不总是表示对象具有 由另一个线程同时修改。如果是单线程 发出一系列违反合同的方法调用 一个对象,该对象可能抛出此异常。例如,如果是 线程在迭代时直接修改集合 使用失败快速迭代器进行集合,迭代器将抛出此异常 异常。
在递归函数中,您有以下场景:
在你走到树的叶子前一步:
假设您有一个父节点“5”是唯一的子节点(叶子)节点“11”。 (“11”有“5”作为其父母)
你开始迭代孩子(“11”),并在他身上调用copyHierarchy
由于他没有孩子,所以循环被跳过,他的父母变为newNode,例如“17”
然后你返回一级。
您应该在以“5”作为父节点的节点上进行迭代,但节点“11”实际上已将其父节点从“5”更改为“17”。
答案 1 :(得分:1)
这是解决方案,有效。我没有对实际问题进行本地化,但我已经成功解决了所有问题......
public TreeNode constructActualModel(TreeAutocompleteMatcherIface matcher) {
if (prunedModel == null) {
eraseHierarchyStructure();
prunedModel = copyHierarchy((TreeNode) completeModel, getVisibleNodes(matcher));
}
return prunedModel;
}
/**
* Recursively copy the hierarchy and prune not visible branches
* @param originalNode node of the original hierarchy to be copied
* @param visibleNodes set of nodes, which should be included in the new hierarchy
* @param model model of the TreeAutompleteComponent
* @return copy of the oroginal node in the new hierarchy
*/
private TreeNode copyHierarchy(TreeNode originalNode, Set<TreeNode> visibleNodes) {
if (!visibleNodes.contains(originalNode)) {
return null;
}
TreeNode newNode = this.getCompleteModelNodes().get(((NodeWrapper) originalNode.getData()).getIri());//new DefaultTreeNode(originalNode.getData(), parent);
List<TreeNode> children = new ArrayList<TreeNode>();
for (int i = 0; i < originalNode.getChildCount(); i++) {
TreeNode child = copyHierarchy((TreeNode) originalNode.getChildren().get(i), visibleNodes);
if(child != null){
children.add(child);
}
}
((DefaultTreeNode) newNode).setChildren(children);
return newNode;
}
private void eraseHierarchyStructure() {
for (TreeNode node : duplicateCompleteModelNodes.values()) {
node.setParent(null);
}
}
有必要以相反的方式执行 - 让impl能够调用setChildren方法并首先擦除层次结构......