问题出在以下背景下#{cc}
以及复合属性的状态性。这#{cc}
在嵌套复合引用的任何属性中itself而不是父母。该属性是有状态的意味着#{cc}
对每个孩子进行重新评估,最终参考itself而不是父母。因此堆栈溢出。它在无限循环中评估自身的深度。
我通过使用支持组件使其无状态来欺骗属性的有状态性,如下所示,该组件立即评估它并将其分配为组件属性:
@FacesComponent("treeComposite")
public class TreeComposite extends UINamingContainer {
private Integer depth;
@Override
public void setValueExpression(String name, ValueExpression binding) {
if ("depth".equals(name)) {
setDepth((Integer) binding.getValue(getFacesContext().getELContext()));
}
else {
super.setValueExpression(name, binding);
}
}
public Integer getDepth() {
return depth;
}
public void setDepth(Integer depth) {
this.depth = depth;
}
}
这是要在接口中声明的componentType
如下:
<cc:interface componentType="treeComposite">
<cc:attribute name="depth" type="java.lang.Integer" />
</cc:interface>
并且,在实现中,您应该在测试中引用无状态属性,并在嵌套复合引用中引用父级属性(因为#{cc}
在嵌套组合的属性中引用嵌套组合本身):
<cc:implementation>
<br />We're at depth #{cc.depth}.
<c:if test="#{cc.depth gt 0}">
<my:tree depth="#{cc.parent.depth - 1}" />
</c:if>
</cc:implementation>
我只是将此处“深度”的含义更改为相反,以便它只是客户端的声明,而无需在实现中对其进行编辑。所以,在客户端你必须说depth="#{3}"
如果你想要 3 个嵌套的孩子:
<my:tree depth="#{3}" />
请注意它是 EL 表达式而不是文字的重要性。否则setValueExpression()
在支持组件中不会被调用。