如果在嵌套复合组件中使用,#{cc} 正在解决 omnifaces 树中的错误

#{cc} is resolving wrong in omnifaces tree if used in nested composite components

参见以下简化代码:

test.xhtml

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:o="http://omnifaces.org/ui"
      xmlns:test="http://xmlns.jcp.org/jsf/composite/test">
    <body>
        <h:form>
            <h1>Nested - not working</h1>
            <test:parentComp />

            <h1>Not nested - working</h1>
            <o:tree value="#{testModel.treeModel}">
                <o:treeNode>
                    <ul>
                        <o:treeNodeItem>
                            <test:childComp />
                            <o:treeInsertChildren />
                        </o:treeNodeItem>
                    </ul>
                </o:treeNode>
            </o:tree>
        </h:form>
    </body>
</html>

parentComp.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:o="http://omnifaces.org/ui"
      xmlns:cc="http://xmlns.jcp.org/jsf/composite"
      xmlns:test="http://xmlns.jcp.org/jsf/composite/test">
    <cc:interface componentType="parentComp">
    </cc:interface>

    <cc:implementation>
        <div id="#{cc.clientId}">
            <o:tree value="#{cc.treeModel}">
                <o:treeNode>
                    <ul>
                        <o:treeNodeItem>
                            <test:childComp />
                            <o:treeInsertChildren />
                        </o:treeNodeItem>
                    </ul>
                </o:treeNode>
            </o:tree>
        </div>
    </cc:implementation>
</html>

childComp.xhtml

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:cc="http://xmlns.jcp.org/jsf/composite"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <cc:interface componentType="childComp">
    </cc:interface>

    <cc:implementation>
        <div id="#{cc.clientId}">
            <h:commandLink action="#{cc.childAction}" value="Click" />
        </div>
    </cc:implementation>
</html>

ParentComponent.java

@FacesComponent("parentComp")
public class ParentComponent extends UINamingContainer {

    private TreeModel treeModel;

    public ParentComponent() {
        this.treeModel = new ListTreeModel();
        this.treeModel.addChild("1").addChild("1.1");
        this.treeModel.addChild("2").addChild("2.2");
    }

    public TreeModel getTreeModel() {
        return treeModel;
    }
}

ChildComponent.java

@FacesComponent("childComp")
public class ChildComponent extends UINamingContainer {

    public void childAction() {

    }
}

TestModel.java

@RequestScoped
@Named
public class TestModel {

    private TreeModel treeModel;

    public TestModel() {
        this.treeModel = new ListTreeModel();
        this.treeModel.addChild("1").addChild("1.1");
        this.treeModel.addChild("2").addChild("2.2");
    }

    public TreeModel getTreeModel() {
        return treeModel;
    }
}

示例中复合组件中使用了o:tree,子组件的#{cc}解析错误,点击link会得到一个像这样的异常:

Caused by: javax.el.MethodNotFoundException: /resources/test/childComp.xhtml @10,71 action="#{cc.childAction}": Method not found: ParentComponent@422dcfd4.childAction()

如果 o:tree 没有像第二个示例那样嵌套在复合组件中,命令 link 将按预期工作。

这是 Omnifaces 中的错误吗?我是不是做错了什么?

这确实是 OmniFaces 中的一个错误。我在 this commit 中修复了它,修复程序在今天的 2.3 快照中可用(2.3 最终版本预计在本周结束,所以你很准时)。

原因是,排队的动作事件基本上是 caught and wrapped by <o:tree> 以便它可以记住当前迭代的树节点,它被触发。但是,在广播动作事件时,它是在 <o:tree> 本身上调用的,而不是在源组件(您的命令 link)上调用的。因此,只有 <o:tree> 上下文中的 #{cc} 本身才被视为复合组件父级。

我通过 pushing 将源组件自己的复合组件父级(如果有)修复到 EL 上下文中。

Original Tree#broadcast() method:

wrapped.getComponent().broadcast(wrapped);

Fixed Tree#broadcast() method:

UIComponent source = wrapped.getComponent();
pushComponentToEL(context, getCompositeComponentParent(source));

try {
    source.broadcast(wrapped);
}
finally {
    popComponentFromEL(context);
}

感谢您的举报!