#目的
複合コンポーネントの引数として受け取った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