Tomcat7サーバーにデプロイされたJSF2Mojarra、RichFaces 4.1、およびEL2.2を使用しています。
私のページには、同じフォームに2つのa4j:regionsが含まれています。一番上の領域は、エンティティのdataTableリストです。下部の領域は詳細エディタパネルです。リストからエンティティを選択すると、その詳細が編集パネルに読み込まれます。詳細パネルには、独自の検証ルールと送信ボタンがあります。2番目のエンティティを詳細フォームにロードするときに、JSFが送信された値を検証エラーでリセットしないという、かなりよく知られている問題に遭遇しました。
この問題を解決するための調査で、私はBalusCからこのブログに出くわしました。彼はリセットの問題を非常にうまく分解し、この問題を解決するためにこのJSF2アクションリスナーを推奨しています。
私は、faces-config.xmlで定義されたアクションリスナーとしてResetInputAjaxActionListenerをプロジェクトに組み込みました。ただし、現在、コードは失敗していますが、リスナーがないと機能しています(送信された/ローカル/モデルの値をリセットしないだけです)。
私のJSFページにはdataTableが含まれており、各行には、行のエンティティをエディターにロードするための編集commandLinkがあります。
<a4j:commandLink action="#{editController.load(entity.id)}" render="@form" execute="@this" value="Edit"/>
EL 2.2を使用しているので、エンティティの主キーを直接loadメソッドに渡します。アクションリスナーがない場合、これは期待どおりに機能します。ただし、action-listenerを有効にすると、コードは次の例外をスローします。
Caused by: javax.faces.FacesException: #{editController.load(entity.id)}: java.lang.NullPointerException
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:110)
at com.buksoft.automaint.web.util.ResetInputAjaxActionListener.processAction(ResetInputAjaxActionListener.java:163)
at javax.faces.component.UICommand.broadcast(UICommand.java:315)
at org.richfaces.component.RowKeyContextEventWrapper.broadcast(RowKeyContextEventWrapper.java:104)
at org.richfaces.component.UIDataAdaptor.broadcast(UIDataAdaptor.java:452)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
... 51 more
Caused by: javax.faces.el.MethodNotFoundException: java.lang.NullPointerException
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:104)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
... 58 more
Caused by: java.lang.NullPointerException
at java.lang.Class.isAssignableFrom(Native Method)
at org.apache.el.util.ReflectionUtil.isAssignableFrom(ReflectionUtil.java:299)
at org.apache.el.util.ReflectionUtil.getMethod(ReflectionUtil.java:172)
at org.apache.el.parser.AstValue.invoke(AstValue.java:251)
at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:278)
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)
... 59 more
EL引数の値がnullに設定されているように見えます。これにより、ELがアクションメソッドのパラメーターにnullをバインドしようとすると、NullPointerExceptionが発生します。これはLong値であると予想されます。
さて、本当に困惑している部分について。エラーを絞り込むために、ResetInputAjaxActionListenerの機能をコメントアウトして、基本的に読み取り専用になるようにしました。私が見つけたのは、findAndAddEditableValueHolders()メソッドのこれらの行が実行されると、ResetInputAjaxActionListenerが完了した後に呼び出されるActionListenerImpl.processAction()によって例外がスローされることです。
if (target instanceof EditableValueHolder) {
inputs.add((EditableValueHolder) target);
}
else if (context.getIdsToVisit() != VisitContext.ALL_IDS) {
// Render ID didn't point an EditableValueHolder. Visit all children as well.
findAndAddEditableValueHolders(VisitContext.createVisitContext(
context.getFacesContext(), null, context.getHints()), target, inputs);
}
上でリンクされているResetInputAjaxActionListenerクラスのfindAndAddEditableValueHolders()メソッドを参照してください。
そして、トラブルコードは実際にはelse ifにのみ存在します。これは、メソッド自体への再帰的な呼び出しであるため、私を混乱させます。これは、createVisitContext()メソッドがバッキングビューツリーを変更している場合とほぼ同じです。私が言ったように、実際の変更を行うすべての変更コードを取り除き、このツリー訪問コード(読み取り専用)を実行すると、例外がスローされます。
コンポーネントツリーにアクセスして(そしてその中の何も変更せずに)、ELメソッドの引数機能を壊す可能性があることを誰かが説明できますか?