复合组件中的阶段侦听器永远不会被调用

时间:2012-08-14 10:11:29

标签: java jsf jsf-2 composite-component phaselistener

我有一个复合组件:

<cc:interface componentType="com.example.MyComponent">
    <!-- ... -->
</cc:interface>

<cc:implementation>
    <f:phaseListener binding="#{cc}"/>
    <div id="#{cc.clientId}">
        <!-- ... -->
    </div>
</cc:implementation>

及其班级:

@FacesComponent("com.example.MyComponent")
public class MyComponent extends UIOutput implements NamingContainer, PhaseListener
{
    @Override
    public String getFamily()
    {
        return "javax.faces.NamingContainer";
    }

    @Override
    public PhaseId getPhaseId()
    {
        return PhaseId.ANY_PHASE;
    }

    @Override
    public void beforePhase(PhaseEvent event)
    {
        // Do something ...
    }

    @Override
    public void afterPhase(PhaseEvent event)
    {
        // Do something ...
    }
}

在任何情况下都不会调用beforePhase(PhaseEvent)afterPhase(PhaseEvent)方法,无论是完整页面加载还是部分页面加载。

我在这里注意到这个错误:http://java.net/jira/browse/JAVASERVERFACES-1200,但它似乎已经修复了很久。

我在Java 6u33 x64上使用GlassFish 3.1.2.2。

1 个答案:

答案 0 :(得分:1)

#{cc}每次beforePhase()实际需要执行afterPhase()<f:phaseListener> UIViewRoot方法时,都会重新评估#{cc}。那时EL范围内没有binding。它仅在组件范围内可用。

如果public MyComponent() { FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("ccc", this); } 在复合组件的构造函数中指向至少一个请求作用域变量,它可以正常工作:

<f:phaseListener binding="#{ccc}" />

<f:phaseListener>

如果你有多个这种类型的复合组件,那么这个结构只会失败。

您最好寻找替代方法:完全摆脱public MyComponent() { FacesContext.getCurrentInstance().getViewRoot().addPhaseListener(this); } 并在复合组件的构造函数中使用UIViewRoot#addPhaseListener()

"javax.faces.NamingContainer"

对具体问题

无关,最好使用UINamingContainer.COMPONENT_FAMILY常量而不是硬编码{{1}}。