jsf-2 - JSF : how prevent stackoverflow due to recursion during build phase (despite rendered test)

标签 jsf-2 recursion stack-overflow

很抱歉没有在专门的测试用例中抽象出这个问题,我希望真实项目中的示例足够简单来描述问题。

我有一个 JavaEE/JPA2/JSF Web 应用程序,其中每个 @Entity 元素(或子类)都有一个模板化的 view.xhtml 页面和一个标准的链接生成器复合组件 util:view_link.xhtml,以 GET 方式调用,数据库 ID 为范围。每个 View 页面的一部分(仅)代表专家系统摘要;该部分可以抽象为复合组件,以包含在 View 页面或其他地方。

我引入了一个 Primefaces p:dialog 模式弹出窗口,用于在单击 View 链接旁边显示的小状态图标时显示专家系统摘要部分(以及任何其他诊断)。如果让状态图标用 x 表示,它看起来像这样:

x Link_to_Element_by_ID

单击“Link_to_Element_by_ID”,它会显示完整 View 页面。

单击“x”图标(专家系统测试失败指示器),弹出带有专家系统摘要的 p:dialog(仅)。

因此 View 页面的专家系统部分被共享为一个复合组件。

但这可能会导致递归和 Stackoverflow,如果:

  1. 弹出的 p:dialog 专家系统摘要显示被检查元素的状态图标指示器。

  2. 我包括其他元素 View 链接以及状态指示器(它们本身会启动一个专家系统摘要的 p:dialog)。

我曾尝试使用递归阻止属性“preventRecursionOnDialog”进行渲染测试,但它失败了,显然是因为递归发生在构建阶段。

问:如何使用测试变量阻止可能的递归?

此外,我尝试了 c:if 测试而不是 JSF“渲染”测试,但似乎测试的变量在 @ViewScoped 下不可用。

例如,对于一个 Activity 元素,其中 util_primefaces:dialog_summary 只是对 p:dialog 的自定义封装。

来自 util:status_activity.xhtml:

     <composite:attribute 
        name="activity"
        required="true"
        type="com.example.entity.Activity"
      />
    <composite:attribute
        name="preventRecursionOnDialog"
        required="false"
        default="false"
        type="java.lang.Boolean"
        />
</composite:interface>

<composite:implementation> 
    <util_primefaces:dialog_summary 
        header="Expert system summary report"
        rendered="#{not cc.attrs.preventRecursionOnDialog}"
        element="#{cc.attrs.activity}">

        <!-- causes StackOverflowError -->

        <util:warn_insufficient_subactivities 
            activityContainer="#{cc.attrs.activity}"
            humanTypeDescription="composite activity"
            preventRecursionOnDialog="true"
            />

        <util:expertsystem_activity activity="#{cc.attrs.activity}"/>

    </util_primefaces:dialog_summary>
    ..
    <span 
        onclick="#{not cc.attrs.preventRecursionOnDialog ? ('dialog'.concat(cc.attrs.activity.id).concat('.show();')) : ''}" 
        style="float:left;" 
        class="icon-completed-#{cc.attrs.activity.acceptedEffective}-small"
        title=".."
        >&nbsp;</span>

util:warn_insufficient_subactivities(显示复合事件的哪些子事件未通过专家系统测试)可能导致递归:

    <cc:interface>
    <cc:attribute name="activityContainer" required="true" type="com.example.entity.IActivityContainer"/>
    <cc:attribute name="humanTypeDescription" required="true" type="java.lang.String"/>
    <cc:attribute
        name="preventRecursionOnDialog"
        required="false"
        default="false"
        type="java.lang.Boolean"
        /> 
</cc:interface> 

<cc:implementation>     
    <h:panelGroup 
        rendered="#{not cc.attrs.activityContainer.sufficientSubActivitiesAccepted}">
        <util:warn_box 
            message=".."
            >
            <!-- CAUTION: can cause Stackoverflow when list included in expertsystem p:dialog popup -->
            <util:list_activity_compact 
                list="#{cc.attrs.activityContainer.activities}" 
                preventRecursionOnDialog="#{cc.attrs.preventRecursionOnDialog}"
                rendered="#{not cc.attrs.preventRecursionOnDialog}"
                />                
        </util:warn_box>

并且 util:list_activity_compact 显示了一个带有状态图标指示器的列表(它反过来可以提供一个带有专家系统摘要的弹出式 p:dialog,并且可以递归)和 util:view_link:

    <cc:interface>

    <cc:attribute 
        name="list" required="true" type="java.util.List"
        />

    <cc:attribute
        name="preventRecursionOnDialog"
        required="false"
        default="false"
        type="java.lang.Boolean"
        />

</cc:interface>

<cc:implementation>
    <h:panelGroup display="block">
        <ul class="view-field-list-medium">
            <ui:repeat var="a" value="#{cc.attrs.list}">
                <li class="view-field-list">
                    <util:status_activity 
                        activity="#{a}" 
                        preventRecursionOnDialog="#{cc.attrs.preventRecursionOnDialog}"/> 
                    <util:view_link element="#{a}"/>
                </li>
            </ui:repeat>
        </ul>
    </h:panelGroup>
</cc:implementation>

问题的重点是测试 rendered="#{not cc.attrs.preventRecursionOnDialog}"不足以阻止递归,即使不会呈现将递归的部分(被渲染测试阻止) ,递归似乎仍然可以在 JSF 构建阶段发生。


顺便说一句,当我只想在类型选择的子集中呈现绑定(bind)到类型的特定复合组件时,我经常会遇到类似的问题;在“呈现”中执行类型测试不足以防止类型错误。想象一下,'value' 可能是包括 Activity 在内的许多 Element 子类之一,但只想显示 Activity 的以下复合组件部分:

        <util:component_for_Activity_only 
            activity="#{cc.attrs.value}"
            rendered="#{cc.attrs.value['class'].simpleName=='Activity'}"
            />

(参见 instanceof check in EL expression language ,并注意基于 Class String 的类型测试解决方案不是很灵活,它不适用于子类或接口(interface)测试。)

同样,尝试用“渲染”来阻止调用是不够的,似乎类型测试在构建阶段就已经失败了。递归问题的解决方案也将为此提供解决方案。即使在 JSF2 中(最后)引入 instanceof(请在这里投票 http://java.net/jira/browse/JSP_SPEC_PUBLIC-113)如果仅用于“渲染”,也无济于事,

最佳答案

在进一步研究和试验后回答自己的问题。

首先,感谢meriton,您的回答并没有完全回答我的问题,而是让我走上了正确的道路。

简短的回答是,自 Mojarra 2.1.18 以来,您可以在 @ViewScoped 的构建阶段使用 c:if 测试来控制递归。就我而言,这现在有效:

        <c:if test="#{not cc.attrs.preventRecursionOnDialog}">

像往常一样,BalusC 对其他帖子的贡献包括:

https://java.net/jira/browse/JAVASERVERFACES-1492

JSF2 Viewscope validation issue

http://balusc.blogspot.com.au/2010/06/benefits-and-pitfalls-of-viewscoped.html

JSTL in JSF2 Facelets... makes sense?

What are the main disadvantages of Java Server Faces 2.0?

我认为这件事对任何使用 JSF 的人都非常重要!在 @ViewScoped 中控制构建内容(而不是呈现内容)的能力可以轻松解决许多问题并开辟许多可能性,我建议任何认真使用 JSF 的人花时间阅读 BalusC 在以上链接。

BalusC,如果您读到这篇文章,请知道您是 JavaServer Faces 和 Enterprise Java 的真正英雄。我代表每一位 JSF 爱好者向你们表示感谢。

感谢 Ed Burns 和 Ted Goddard 在报告和修复此问题方面所做的出色工作:https://java.net/jira/browse/JAVASERVERFACES-1492这是对 JSF2 的重大改进。

最后,我不得不使用一个肮脏的技巧在 NetBeans7.1+Glassfish3.1.1 上安装 Mojarra 2.1.21(由于第 3 方不兼容而需要),如下所述:JSF how upgrade to Mojarra 2.1.21 in Netbeans7.1 (just sub jsf-api.jar and jsf-impl.jar fails)

这对我的项目来说是一个很好的结果。如果没有 Stackoverflow 我该怎么办 :)

关于jsf-2 - JSF : how prevent stackoverflow due to recursion during build phase (despite rendered test),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16665705/

相关文章:

arrays - 设置数组(记录)长度时,Delphi 堆栈溢出和访问冲突错误

java - 为什么我需要在此处的 Managed Bean 中显式创建 ArrayList 的实例?

java - 我如何使用 <h :outputScript/> with a remote file?

java - 在jsf中显示图像

c# - 在随机生成的迷宫上使用递归回溯

C# - System.StackOverflowException 与 Lambda

java - JSF - JUnit FacesContext 模拟测试

java - 递归对象设置java

java - 我如何告诉快速排序算法它应该终止?

C# WPF Window.ShowDialog 堆栈溢出异常