JSF: как предотвратить переполнение стека из-за рекурсии на этапе сборки (несмотря на визуализацию теста)

Извиняюсь за то, что не абстрагировал эту проблему в специальном тестовом примере, я надеюсь, что пример из реального проекта достаточно прост, чтобы описать проблему.

У меня есть веб-приложение JavaEE / JPA2 / JSF, где каждый элемент @Entity (или подкласс) имеет шаблонную страницу view.xhtml, и стандартный составной компонент генератора ссылок util: view_link.xhtml, вызываемый как GET с идентификатором базы данных в качестве параметра. Часть (только) каждой страницы представления представляет сводку экспертной системы; эта часть может быть абстрагирована как составной компонент для включения в страницу просмотра или в другое место.

Я представил модальное всплывающее окно Primefaces p: для отображения этой сводной части экспертной системы (и любой дополнительной диагностики) при нажатии на маленький значок состояния, отображаемый рядом со ссылкой просмотра. Если вы позволите значку состояния быть представленным как x, это будет выглядеть так:

x Link_to_Element_by_ID

Нажмите «Link_to_Element_by_ID», и появится страница полного просмотра.

Нажмите на значок «x» (индикатор сбоя теста экспертной системы), и появится всплывающее диалоговое окно p: со сводкой экспертной системы (только).

Таким образом, часть экспертной системы страницы просмотра является составным компонентом.

Но это может привести к рекурсии и Stackoverflow, если либо:

В всплывающей сводке системы p: dialog expert отображается индикатор значка состояния проверяемого элемента.

Я включаю дополнительные ссылки для просмотра элементов вместе с индикаторами состояния (которые сами запускают диалог p: для сводки экспертной системы).

Я пытался использовать визуализированные тесты с использованием атрибута блокировки рекурсии 'protectRecursionOnDialog', но это не удалось, по-видимому, потому что рекурсия происходит на этапе сборки.

Q: Как я могу заблокировать возможную рекурсию, используя тестовую переменную?

Кроме того, я пробовал c: if тесты вместо «визуализированных» тестов JSF, но кажется, что тестируемая переменная недоступна в @ViewScoped.

Пример для элемента Activity, где util_primefaces: dialog_summary - это просто настраиваемая инкапсуляция диалога p :.

Из 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: с краткой сводкой экспертной системы и может повторяться) и 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.

Кстати, я часто сталкиваюсь с подобной проблемой, когда я хочу визуализировать только конкретный составной компонент, связанный с типом, в подмножестве вариантов выбора; Выполнение проверки типа в 'rendered' недостаточно для предотвращения ошибки типа. Ниже представьте, что 'value' может быть одним из многих подклассов Element, включая Activity, но для отображения Activity требуется только отображать следующую составную часть компонента:

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

(Српроверка экземпляра на языке выражений ELи обратите внимание, что это решение для тестирования типов на основе класса String не очень гибкое, оно не работает для подклассов или тестов интерфейса.)

Опять же, попытки заблокировать вызовы с помощью метода «rendered» недостаточно, похоже, что проверка типа не удалась уже на этапе сборки. Решение проблемы рекурсии также может предложить решение этой проблемы. Даже введение (наконец) instanceof в JSF2 (голосуйте здесь, пожалуйстаhttp://java.net/jira/browse/JSP_SPEC_PUBLIC-113) не помогло бы здесь, если бы использовалось только в 'rendered',

Ответы на вопрос(2)

Ваш ответ на вопрос