导致堆栈溢出异常的嵌套 JSF 复合组件 [英] Nested JSF Composite Components leading to a Stack Overflow exception

查看:25
本文介绍了导致堆栈溢出异常的嵌套 JSF 复合组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我尝试在自身内部嵌套一个复合组件时,使用一些逻辑来结束无限递归,我收到堆栈溢出异常.我的理解是 标签在视图构建时运行 所以我是不希望像我认为的那样构建无限视图.

When I attempt to nest a Composite Component within itself, with some logic to end the infinite recursion I receive a stack overflow exception. My understanding is that <c:xxx> tags run at view build time so I was not expecting to have an infinite view build as I presume has been the case.

这是复合组件simpleNestable.xhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:composite="http://java.sun.com/jsf/composite"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:em="http://xmlns.jcp.org/jsf/composite/emcomp"

  xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">

    <h:head>
        <title>This content will not be displayed</title>
    </h:head>
    <h:body>
        <composite:interface>
            <composite:attribute name="depth" required="true" type="java.lang.Integer"/>
        </composite:interface>

        <composite:implementation>
            <c:if test="#{cc.attrs.depth lt 3}">
                 #{cc.attrs.depth}
                 #{cc.attrs.depth+1}
                 <em:simpleNestable depth="#{cc.attrs.depth+1}" /> 

            </c:if>

        </composite:implementation>
    </h:body>
</html>

这是它的用法

<h:head>
    <title>Facelet Title</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <h:outputStylesheet name="./css/default.css"/>
    <h:outputStylesheet name="./css/cssLayout.css"/>
</h:head>
<h:body>        
     <emcomp:simpleNestable depth="1"/>

</h:body>

堆栈溢出异常

java.lang.StackOverflowError
    at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
    at javax.faces.component.UIComponentBase$AttributesMap.get(UIComponentBase.java:2407)
    at com.sun.faces.el.CompositeComponentAttributesELResolver$ExpressionEvalMap.get(CompositeComponentAttributesELResolver.java:393)
    at javax.el.MapELResolver.getValue(MapELResolver.java:199)
    at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
    at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
    at com.sun.el.parser.AstValue.getValue(AstValue.java:140)
    at com.sun.el.parser.AstValue.getValue(AstValue.java:204)
    at com.sun.el.parser.AstPlus.getValue(AstPlus.java:60)
    at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:226)
    at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
    at com.sun.faces.facelets.el.ContextualCompositeValueExpression.getValue(ContextualCompositeValueExpression.java:158)
    at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
    at javax.faces.component.UIComponentBase$AttributesMap.get(UIComponentBase.java:2407)
    at com.sun.faces.el.CompositeComponentAttributesELResolver$ExpressionEvalMap.get(CompositeComponentAttributesELResolver.java:393)
    at javax.el.MapELResolver.getValue(MapELResolver.java:199)
    at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
    at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
    at com.sun.el.parser.AstValue.getValue(AstValue.java:140)
    at com.sun.el.parser.AstValue.getValue(AstValue.java:204)
    at com.sun.el.parser.AstPlus.getValue(AstPlus.java:60)

问题

如何在不接收堆栈溢出异常的情况下将复合组件(或类似组件)嵌套在其内部(到非预定义的深度)

The Question

How can I nest composite components (or similar) within themselves (to a non predefined depth) without receiving a stack overflow exception

我想在 RichFaces 的嵌套 collapsibleSubTable 中表示任意嵌套的数据,非常欢迎替代我的方法

I have arbitrarily nested data that I want to represent within a nested collapsibleSubTable from RichFaces, alternatives to my approach are very welcome

推荐答案

问题出在 #{cc} 的上下文和复合属性的状态.嵌套复合的任何属性中的 #{cc} 引用 自身 而不是父级.有状态的属性意味着 #{cc} 在每个孩子中重新评估,最终引用自身而不是父级.因此堆栈溢出.它正在无限循环中评估自身的深度.

The problem was in the context of the #{cc} and the statefulness of the composite attribute. The #{cc} in any attribute of the nested composite references itself instead of the parent. The attribute being stateful means that the #{cc} was re-evaluated in every child which in turn ultimately references itself instead of the parent. Hence the stack overflow. It's evaluating the depth of itself in an infinite loop.

我通过使用支持组件使其无状态来欺骗属性的状态,如下所示,该组件立即评估它并将其分配为组件属性:

I tricked the statefulness of the attribute by making it stateless using a backing component as below which immediately evaluates it and assigns it as a component property:

@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} 引用了嵌套复合本身):

And, in the implementation you should in the test reference the stateless property and in the nested composite reference the one of the parent (because #{cc} in the attribute of the nested composite references the nested composite itself):

<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>

我在这里只是将深度"的含义改为相反的方式,这样它就只是从客户端开始声明,而无需在实现中对其进行编辑.所以,如果你想要 3 个嵌套的孩子,你必须在客户端说 depth="#{3}":

I only changed the meaning of "depth" here to be the other way round so that it's just declarative from the client on without the need to edit it in the implementation. So, in the client you have to say depth="#{3}" if you want 3 nested children:

<my:tree depth="#{3}" />

请注意它是 EL 表达式而不是文字的重要性.否则将不会调用支持组件中的 setValueExpression().

Note the importance of it being an EL expression rather than a literal. Otherwise setValueExpression() in the backing component won't be called.

这篇关于导致堆栈溢出异常的嵌套 JSF 复合组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆