web-dev-qa-db-ja.com

JSF 2-Ajaxリスナーメソッドを複合コンポーネントインターフェイスに追加するにはどうすればよいですか?

いくつかのAjax動作を使用するJSF 2複合コンポーネントがあります。複合コンポーネント内の<f:ajax>タグにlistenerメソッドを追加したいのですが、listenerメソッドを<composite:attribute><composite:interface>として提供する必要があります。

私の複合コンポーネント内の<f:ajax>タグは現在、次のようなリスナーにハードコードされています。

<f:ajax
    event="valueChange"
    execute="@this"
    listener="#{controller.genericAjaxEventLogger}"
    render="#{cc.attrs.ajaxRenderTargets}" />

Beanのリスナーメソッドには次のシグネチャがあります。

public void genericAjaxEventLogger(AjaxBehaviorEvent event) 
        throws AbortProcessingException {
    // implementation code...
}

複合コンポーネントをこのようなものにして、ページが独自のイベントメソッドを提供できるようにしたいのですが、インターフェースの正しい構文を理解できません。

<f:ajax
    event="valueChange"
    execute="@this"
    listener="#{cc.attrs.ajaxEventListener}"
    render="#{cc.attrs.ajaxRenderTargets}" />

どうすればよいですか?

ソリューションで更新:

私はBalusCによって提案されたアプローチを採用しましたが、それはうまく機能します。関連するスニペットは次のとおりです。

複合コンポーネントのインターフェース宣言

<composite:interface>
    <composite:attribute
        name="myattributeUpdatedEventListener"
        method-signature="void listener()"
        required="true" />
    ...
</composite:interface>

複合コンポーネントで使用されるAjaxタグ

<f:ajax
    event="valueChange"
    execute="@this"
    listener="#{cc.attrs.myattributeUpdatedEventListener}"
    render="#{cc.attrs.ajaxRenderTargets}" />

複合コンポーネントを使用するページ内の場所

<h:form>
    <compcomp:myCompositeComponent
        myattributeUpdatedEventListener="#{myBackingBean.updatedEventListenerXYZ}" />
</h:form>

そして私のバッキングビーンズの方法

public void updatedEventListenerXYZ() {
    // do something here...
}
22
Jim Tough

もしcanAjaxBehaviorEvent引数を取り除くなら、

public void genericAjaxEventLogger() {
    // ...
}

その後、あなたは使うことができます

<cc:attribute name="ajaxEventListener" method-signature="void listener()" />

引数が必須である場合(ロギング用?)、次のように属性を再指定する必要があります。

<cc:attribute name="ajaxEventListener" method-signature="void listener(javax.faces.event.AjaxBehaviorEvent)" />

ただし、これは期待どおりには機能しません

<f:ajax listener="#{cc.attrs.ajaxEventListener}" />

GF 3.1 + Mojarra 2.1.1:

SEVERE: javax.faces.FacesException: wrong number of arguments
    at com.Sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.Java:89)
    at com.Sun.faces.lifecycle.Phase.doPhase(Phase.Java:101)
    at com.Sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.Java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.Java:409)
    at org.Apache.catalina.core.StandardWrapper.service(StandardWrapper.Java:1534)
    at org.Apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.Java:281)
    at org.Apache.catalina.core.StandardContextValve.invoke(StandardContextValve.Java:175)
    at org.Apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.Java:655)
    at org.Apache.catalina.core.StandardPipeline.invoke(StandardPipeline.Java:595)
    at com.Sun.enterprise.web.WebPipeline.invoke(WebPipeline.Java:98)
    at com.Sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.Java:91)
    at org.Apache.catalina.core.StandardHostValve.invoke(StandardHostValve.Java:162)
    at org.Apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.Java:326)
    at org.Apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.Java:227)
    at com.Sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.Java:170)
    at com.Sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.Java:822)
    at com.Sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.Java:719)
    at com.Sun.grizzly.http.ProcessorTask.process(ProcessorTask.Java:1013)
    at com.Sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.Java:225)
    at com.Sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.Java:137)
    at com.Sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.Java:104)
    at com.Sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.Java:90)
    at com.Sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.Java:79)
    at com.Sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.Java:54)
    at com.Sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.Java:59)
    at com.Sun.grizzly.ContextTask.run(ContextTask.Java:71)
    at com.Sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.Java:532)
    at com.Sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.Java:513)
    at Java.lang.Thread.run(Unknown Source)
Caused by: Java.lang.IllegalArgumentException: wrong number of arguments
    at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at Sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at Sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at Java.lang.reflect.Method.invoke(Unknown Source)
    at com.Sun.el.parser.AstValue.invoke(AstValue.Java:234)
    at com.Sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.Java:297)
    at com.Sun.faces.facelets.el.ContextualCompositeMethodExpression.invoke(ContextualCompositeMethodExpression.Java:177)
    at com.Sun.faces.facelets.tag.TagAttributeImpl$AttributeLookupMethodExpression.invoke(TagAttributeImpl.Java:450)
    at com.Sun.faces.facelets.tag.jsf.core.AjaxBehaviorListenerImpl.processAjaxBehavior(AjaxHandler.Java:447)
    at javax.faces.event.AjaxBehaviorEvent.processListener(AjaxBehaviorEvent.Java:113)
    at javax.faces.component.behavior.BehaviorBase.broadcast(BehaviorBase.Java:102)
    at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.Java:760)
    at javax.faces.component.UICommand.broadcast(UICommand.Java:300)
    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)
    ... 28 more

これがバグかどうかはわかりません。そのため、私はそれを特定するためにもう少し時間を費やす必要があります。ただし、属性からMethodExpressionを取得し、適切な数の引数で呼び出すバッキングコンポーネントを作成することで回避できました。以下は完全なキックオフの例です。

<ui:component 
    xmlns:f="http://Java.Sun.com/jsf/core"
    xmlns:h="http://Java.Sun.com/jsf/html"
    xmlns:cc="http://Java.Sun.com/jsf/composite"
    xmlns:ui="http://Java.Sun.com/jsf/facelets"
>
    <cc:interface componentType="testCC">
        <cc:attribute name="ajaxEventListener" method-signature="void listener(javax.faces.event.AjaxBehaviorEvent)" />
    </cc:interface>
    <cc:implementation>
        <h:commandButton value="Submit">
            <f:ajax listener="#{cc.ajaxEventListener}" />
        </h:commandButton>
    </cc:implementation>
</ui:component>

package com.example;

import javax.el.MethodExpression;
import javax.faces.component.FacesComponent;
import javax.faces.component.UINamingContainer;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;

@FacesComponent(value="testCC")
public class TestCC extends UINamingContainer {

    public void ajaxEventListener(AjaxBehaviorEvent event) {
        FacesContext context = FacesContext.getCurrentInstance();
        MethodExpression ajaxEventListener = (MethodExpression) getAttributes().get("ajaxEventListener");
        ajaxEventListener.invoke(context.getELContext(), new Object[] { event });
    }

}

とにかく、バッキングコンポーネントは、とにかく考えていた機能要件を達成するための新しい方法への扉を開くと思います。;)

26
BalusC

以下は、インターフェースを使用して属性を設定し、実装内でそれを参照する方法の例です。呼び出されるメソッドのmethod-signatureを定義する必要があります。これにより、#{cc.attrs.ajaxEventListener}式に含まれる値式ではなくメソッド値が存在することが複合コンポーネントハンドラーに通知されます。

<cc:interface name="composite-comp"
    <cc:attribute required="true" name="ajaxEventListener" 
                  method-signature="void f1(javax.faces.event.AjaxBehaviorEvent)" />
    <cc:attribute required="true" name="ajaxRenderTargets" />
</cc:interface>

<cc:implementation>
    .
    .
    .
    <f:ajax event="valueChange" execute="@this"
        listener="#{cc.attrs.ajaxEventListener}"
        render="#{cc.attrs.ajaxRenderTargets}" />
</cc:implementation>
2
Jason