1

モデル階層に基づいてのみ実行できる複雑な検証を伴うアプリケーションがあるため、JSF の検証ステージを使用できません。

私の問題は、検証エラーをGUIにリンクする必要があることです(注意が必要なテキストフィールドを視覚的に表示します)。そのため、UI コンポーネントとドメイン モデル アイテムをどこかにリンクする必要があります。

PreRenderComponentEventListener を使用してこれを実現したいと思っていました:

  • 私の検証コンポーネントは、注意が必要なオブジェクトとプロパティにアクセスできる Constraintvalidations を格納します。
  • UIComponent の ValueExpression を使用して、Component がバインドする正しいオブジェクトを取得します。

最初はこれがうまくいくように見えました:私はxhtmlページに次のものを持っています:

<ui:composition template="/templates/mainTemplate.xhtml">
<ui:define name="content">  
   <ui:repeat value="#{contactController.contactManager.contactList}" var="contact">
          <h:inputText value="#{contact.name}"/>
          <h:inputText value="#{contact.firstName}"/>
          <br/>
      </ui:repeat>
</ui:define>
</ui:composition>

ここで、1 つの firstName が失敗した連絡先のリストがあるとします。

ValueExpression の式文字列から「#{contact.firstName}」が得られます。この値から新しい ValueExpression を作成して、親の「#{contact}」を取得し、失敗した名前がリスト内の正しい連絡先の 1 つであるかどうかを確認できます。

だから私は Listener でこのようなことをします:

private Object extractParent(UIInput input) {
   FaceletContext faceletElContext = (FaceletContext) FacesContext.getCurrentInstance().getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
   ValueExpression orig = input.getValueExpression("value");
   String parent = getParent(orig.getExpressionString());
   ValueExpression valueExpression = FacesContext.getCurrentInstance().getApplication().getExpressionFactory().createValueExpression(faceletElContext,"#{"+parent+"}", Object.class);
   return valueExpression.getValue(faceletElContext);
}

現在、これは繰り返しが最上位の facelet にある場合にのみ機能します。
私の複雑なアプリがインクルードファイルを使用するとすぐに、これが2つの理由で失敗し始めます:

  • facelet コンテキストは、ネストされた xhtml のコンテキストではなく、間違ったコンテキストであるため、variableMapper に変数がありません。
  • 変数はUIComponentのvalueexpression自体で定義されていますが、その変数にはアクセスできず、プライベートアクセスしかないため、その変数も使用できません。

だから私は完全に立ち往生しています!誰かが私に代わりを提供できますか?

@BalusC からの応答の評価後の更新: で試しましたELContextが、成功しませんでした。私はもう少し調査しましたが、核となる問題は、インクルードファイルで定義された変数へのアクセスELContextも許可しないことです:FaceletContext

  • ELContextはそれらがありません
  • これはFaceletContext常に最後のインクルード ファイルの 1 つであるように思われるため、正しいファイルではありません。

これを証明する小さなテストケースがあります。「contactinner」入力テキストをレンダリングするとき、ELContext にはこの変数がなく、faceletcontext には間違った xhtml 階層があります。

すべてのヘルプは非常に高く評価されています。

test.xhtml :

<ui:composition>
<h:form id="myform">
    <c:set var="itemContact" value="#{contactController.contact}"/>
    <c:set var="itemPerson" value="#{contactController.person}"/>
    <ui:include src="contact.xhtml"/>
    <ui:include src="person.xhtml"/>
    <h:commandButton action="#{contactController.process}"/>
</h:form>
</ui:composition>

contact.xhtml :

<ui:composition>
     <c:set var="contactinner" value="#{itemContact}"/>
     <h:inputText value="#{contactinner}"/>
</ui:composition>

person.xhtml :

<ui:composition>
    <c:set var="personinner" value="#{itemPerson}"/>
    <h:inputText value="#{personinner}"/>
</ui:composition>

faces-config.xml (抜粋) :

<system-event-listener>
<system-event-listener-class>TestSystemEventListener</system-event-listener-class>
<system-event-class>javax.faces.event.PreRenderComponentEvent</system-event-class>
</system-event-listener>

TestSystemEventListener (抜粋) :

public class TestSystemEventListener implements SystemEventListener {
    @Override
    public void processEvent(SystemEvent event) throws AbortProcessingException {
       UIInput input = (UIInput) event.getSource();
       FaceletContext faceletElContext = (FaceletContext) FacesContext.getCurrentInstance().getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
       FacesContext context = FacesContext.getCurrentInstance();
       ValueExpression orig = input.getValueExpression("value");
}

これを実行すると、最初の xhtml で inputext に対して eventlistener が起動されると、listener で#{contactInner}次のデータが取得されます。

orig = {com.sun.faces.facelets.el.TagValueExpression@24201}"/xhtml/contact.xhtml @6,43 value=\"#{contactinner}\""
    orig = {com.sun.el.ValueExpressionImpl@24220}"ValueExpression[#{contactinner}]"
    expr = {java.lang.String@24270}"#{contactinner}"
    varMapper = {com.sun.el.lang.VariableMapperImpl@24271}
    vars = {java.util.HashMap@24275} size = 1
       [0] = {java.util.HashMap$Entry@24278}"contactinner" -> "/xhtml/contact.xhtml @5,54 value=\"#{itemContact}\""


context = {com.sun.faces.context.FacesContextImpl@24200}
    elContext = {com.sun.faces.el.ELContextImpl@24205}
    functionMapper = {com.sun.faces.facelets.compiler.NamespaceHandler@24284}
    variableMapper = {com.sun.faces.el.ELContextImpl$VariableMapperImpl@24221}
        variables = {java.util.HashMap@24289} size = 2
        [0] = {java.util.HashMap$Entry@24292}"itemContact" -> "/xhtml/test.xhtml @9,68 value=\"#{contactController.contact}\""
        [1] = {java.util.HashMap$Entry@24295}"itemPerson" -> "/xhtml/test.xhtml @10,66 value=\"#{contactController.person}\""           

faceletElContext = {com.sun.faces.facelets.impl.DefaultFaceletContext@24199}
    faces = {com.sun.faces.context.FacesContextImpl@24200}
    ctx = {com.sun.faces.el.ELContextImpl@24205}
    facelet = {com.sun.faces.facelets.impl.DefaultFacelet@24151}"/xhtml/person.xhtml"
    faceletHierarchy = {java.util.ArrayList@24206} size = 2
    [0] = {com.sun.faces.facelets.impl.DefaultFacelet@23792}"/xhtml/test.xhtml"
    [1] = {com.sun.faces.facelets.impl.DefaultFacelet@24151}"/xhtml/person.xhtml"
    varMapper = {com.sun.faces.facelets.el.VariableMapperWrapper@24207}
    target = {com.sun.faces.el.ELContextImpl$VariableMapperImpl@24221}
    vars = {java.util.HashMap@24222} size = 1
        [0] = {java.util.HashMap$Entry@24225}"personinner" -> "/xhtml/person.xhtml @5,52 value=\"#{itemPerson}\""               
4

1 に答える 1

0

ではなく、ELContextによって取得されたインスタンスを使用する必要があります。FacesContext#getELContext()FaceletContext

private Object extractParent(UIInput input) {
    ELContext elContext = FacesContext.getCurrentInstance().getELContext();
    ValueExpression orig = input.getValueExpression("value");
    String parent = getParent(orig.getExpressionString());
    ValueExpression valueExpression = FacesContext.getCurrentInstance().getApplication().getExpressionFactory().createValueExpression(elContext, "#{" + parent + "}", Object.class);
    return valueExpression.getValue(elContext);
}

ちなみに略称はApplication#evaluateExpressionGet().

private Object extractParent(UIInput input) {
    FacesContext context = FacesContext.getCurrentInstance();
    ValueExpression orig = input.getValueExpression("value");
    String parent = getParent(orig.getExpressionString());
    return context.getApplication().evaluateExpressionGet(context, "#{" + parent + "}", Object.class);
}
于 2013-01-04T11:55:37.500 に答える