この問題を専用のテストケースで抽象化していないことをお詫びします。実際のプロジェクトの例が問題を説明するのに十分単純であることを願っています。
すべての @Entity Element (またはサブクラス) にテンプレート化された view.xhtml ページと、データベース ID をパラメーターとして GET として呼び出される標準リンク ジェネレーター複合コンポーネント util:view_link.xhtml がある JavaEE/JPA2/JSF Web アプリケーションがあります。各ビュー ページの一部 (のみ) は、エキスパート システムの概要を表します。その部分は、ビュー ページまたは他の場所に含めるために、複合コンポーネントとして抽象化できます。
表示リンクの横に表示される小さなステータス アイコンをクリックすると、そのエキスパート システムの概要部分 (および追加の診断) を表示するための Primefaces p:dialog モーダル ポップアップを導入しました。ステータス アイコンを x で表すと、次のようになります。
x Link_to_Element_by_ID
「Link_to_Element_by_ID」をクリックすると、フル ビュー ページが表示されます。
「x」アイコン (エキスパート システム テストの失敗インジケータ) をクリックすると、エキスパート システムの概要 (のみ) を含む p:dialog がポップアップします。
そのため、ビュー ページのエキスパート システム部分は複合コンポーネントとして共有されます。
ただし、次のいずれかの場合、再帰と Stackoverflow が発生する可能性があります。
ポップアップ p:dialog エキスパート システム サマリーには、検査中のエレメントのステータス アイコン インジケータが表示されます。
追加の要素ビュー リンクとステータス インジケーターを含めます (エキスパート システムの概要を表示するために ap:dialog を起動します)。
再帰ブロック属性「preventRecursionOnDialog」を使用してレンダリングされたテストを使用しようとしましたが、ビルド段階で再帰が発生しているため、失敗しました。
Q: テスト変数を使用して再帰の可能性をブロックするにはどうすればよいですか?
また、JSF「レンダリング」テストの代わりに c:if テストを試しましたが、テストされた変数は @ViewScoped では使用できないようです。
たとえば、Activity 要素の場合、util_primefaces:dialog_summary は単に ap: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=".."
> </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>
質問のポイントは、再帰する部分がレンダリングされていない(レンダリングされたテストによってブロックされている)にもかかわらず、レンダリングされたテストが再帰をブロックするのに十分ではないということですJSF ビルド フェーズ中に再帰が発生する可能性があります。
ところで、タイプの選択のサブセット内で、タイプにバインドされた特定の複合コンポーネントのみをレンダリングしたい場合、同様の問題に遭遇することがよくあります。「rendered」で型テストを実行するだけでは、型エラーを防ぐのに十分ではありません。以下で、「値」がアクティビティを含む多くの要素サブクラスの 1 つになる可能性があることを想像してください。ただし、アクティビティの次の複合コンポーネント部分のみを表示する必要があります。
<util:component_for_Activity_only
activity="#{cc.attrs.value}"
rendered="#{cc.attrs.value['class'].simpleName=='Activity'}"
/>
( EL 式言語の instanceof チェックを参照してください。クラス文字列ベースの型テスト ソリューションはあまり柔軟ではないことに注意してください。サブクラスやインターフェイス テストでは機能しません。)
繰り返しますが、'rendered' による呼び出しをブロックする試みは十分ではありません。ビルド フェーズ中に型テストが既に失敗しているようです。再帰問題の解決策は、これに対する解決策も提供します。JSF2 での instanceof の (最終的な) 導入 (ここで投票してくださいhttp://java.net/jira/browse/JSP_SPEC_PUBLIC-113 ) でさえ、「レンダリング」でのみ使用される場合、ここでは役に立ちません。