2

私は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)
4

2 に答える 2

2

現在繰り返し処理しているコレクションを変更しようとしています。
現在のコレクションを変更する代わりに、問題のコレクションのコピーで作業してみましたか?

http://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.htmlから:

この例外は、オブジェクトが別のスレッドによって同時に変更されたことを常に示しているわけではないことに注意してください。単一のスレッドがオブジェクトのコントラクトに違反する一連のメソッド呼び出しを発行した場合、オブジェクトはこの例外をスローする可能性があります。たとえば、スレッドがフェイルファストイテレータを使用してコレクションを反復処理しているときにコレクションを直接変更すると、イテレータはこの例外をスローします。

再帰関数では、次のシナリオがあります。

ツリーの葉に到達する前の1つのステップ:
親ノード「5」と一人っ子(葉)ノード「11」があるとします。(「11」の親は「5」です)子(「11」)の反復を開始し、彼にcopyHierarchyを呼び出します。
彼には子がいないため、ループはスキップされ、親はnewNode、たとえば「17」になります。
次に、1つ上のレベルに戻ります。
親として「5」を持つノードを反復処理することになっていますが、ノード「11」の親は実際には「5」から「17」に変更されています。

于 2012-07-18T11:23:54.400 に答える
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メソッドを呼び出して、最初に階層を消去できるようにするためです。

于 2012-07-18T12:59:21.840 に答える