LoginSignup
1
0

More than 3 years have passed since last update.

複合コンポーネント内のh:commandButtonに複数のactionListenerを指定する方法

Posted at

目的

複合コンポーネントの引数として受け取ったactionListenerを使用し、h:commandButton、h:commandLinkに複数指定したい際の実装方法です。

問題点

引数のlistener2、3をf:actionListenerで実行しようとしたところエラーとなってしまいました。
※h:commandListenerの属性として指定したlistener1とactionはエラーにならなかった

TestListener.java
public void method1() {
    System.out.println("method1");
}
public void method2() {
    System.out.println("method2");
}
public void method3() {
    System.out.println("method3");
}
public void method4() {
    System.out.println("method4");
}
multiListener.xhtml
<cc:interface>
    <cc:attribute name="listener1" method-signature="void actionListener(javax.faces.event.ActionEvent)"></cc:attribute>
    <cc:attribute name="listener2" method-signature="void actionListener(javax.faces.event.ActionEvent)"></cc:attribute>
    <cc:attribute name="listener3" method-signature="void actionListener(javax.faces.event.ActionEvent)"></cc:attribute>
    <cc:attribute name="action" method-signature="java.lang.Object action()"></cc:attribute>
</cc:interface>
<cc:implementation>
    <h:commandButton value="cc1"
                actionListener="#{cc.attrs.listener1}"
                    action="#{cc.attrs.action}">
        <f:actionListener binding="#{cc.attrs.listener2}"/>
        <f:actionListener binding="#{cc.attrs.listener3}"/>
    </h:commandButton>
</cc:implementation>
Test.xhtml
<my:multiListener listener1="#{testListener.method1()}"
                    listener2="#{testListener.method2()}"
                    listener3="#{testListener.method3()}"
                    action="#{testListener.method4()}"/>
javax.servlet.ServletException: Cannot convert com.sun.faces.facelets.el.ContextualCompositeMethodExpression@70723673 of type class com.sun.faces.facelets.el.ContextualCompositeMethodExpression to interface javax.faces.event.ActionListener
    at javax.faces.api@3.0.0.Final//javax.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:725)
    at javax.faces.api@3.0.0.Final//javax.faces.webapp.FacesServlet.service(FacesServlet.java:451)
    at io.undertow.servlet@2.0.26.Final//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
    at io.undertow.servlet@2.0.26.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
    at io.opentracing.contrib.opentracing-jaxrs2//io.opentracing.contrib.jaxrs2.server.SpanFinishingFilter.doFilter(SpanFinishingFilter.java:52)
    at io.undertow.servlet@2.0.26.Final//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
・・・

実装方法

複合コンポーネントの引数で指定したメソッドは「ContextualCompositeMethodExpression」でラップされる(という表現が正しいかはわからないが)ようで、f:actionListenerを使用する場合はそこを考慮した実装にする必要があるようです。

実装方法①

multiListener.xhtml
<h:commandButton value="cc1"
                actionListener="#{cc.attrs.listener1}"
                action="#{cc.attrs.action}">
    <f:actionListener binding="#{cc.attrs.listener2.invoke(facesContext.getCurrentInstance().getELContext(), null)}"/>
    <f:actionListener binding="#{cc.attrs.listener3.invoke(facesContext.getCurrentInstance().getELContext(), null)}"/>
</h:commandButton>

実装方法②

multiListener.xhtml
<h:commandButton value="cc2"
                action="#{testListener.execute(cc.attrs.listener1,cc.attrs.listener2,cc.attrs.listener3,cc.attrs.action)}">
</h:commandButton>
TestListener.java
    public Object execute(ContextualCompositeMethodExpression listener1
            , ContextualCompositeMethodExpression listener2
            , ContextualCompositeMethodExpression listener3
            , ContextualCompositeMethodExpression action) {
        ELContext el = FacesContext.getCurrentInstance().getELContext();
        listener1.invoke(el, null);
        listener2.invoke(el, null);
        listener3.invoke(el, null);
        return action.invoke(el, null);
    }

結果

①、②ともに以下のようになりました。

14:43:31,276 INFO  [stdout] (default task-1) method1

14:43:31,276 INFO  [stdout] (default task-1) method2

14:43:31,276 INFO  [stdout] (default task-1) method3

14:43:31,277 INFO  [stdout] (default task-1) method4
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0