Search code examples
jsfglassfish-4

How to pass around action outcome to jsf composition?


I have this JSF snippet which works fine. When the commandbutton is clicked it should reload the page by redirecting to itself.

<p:dataTable value="#{fileModel.files}" 
            var="file" scrollable="true" scrollHeight="400">
    <p:column headerText="#{msgs.lbl_file}">
        #{file.name}
    </p:column>
    <p:column width="150">
        <p:commandButton value="#{msgs.lbl_import}" 
            actionListener="#{fileModel.importFile(file, module)}"
            **action="mypage.jsf?faces-redirect=true"**/>
    </p:column>
    <p:column width="150">
        <p:commandLink value="#{msgs.lbl_view}" target="_blank" ajax="false"
            actionListener="#{fileModel.view(file)}"/>
    </p:column>
</p:dataTable>

Because I want to reuse this in multiple pages I tried to make this JSF template and include it via ui:include. Only thing is that I need the action to be configurable depending on the page it is used in.

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
                xmlns:p="http://primefaces.org/ui">
    <p:dataTable value="#{fileModel.files}" 
                var="file" scrollable="true" scrollHeight="400">
        <p:column headerText="#{msgs.lbl_file}">
            #{file.name}
        </p:column>
        <p:column width="150">
            <p:commandButton value="#{msgs.lbl_import}" 
                actionListener="#{fileModel.importFile(file, module)}"
                **action="#{redirectTo}"**/>
        </p:column>
        <p:column width="150">
            <p:commandLink value="#{msgs.lbl_view}" target="_blank" ajax="false"
                actionListener="#{fileModel.view(file)}"/>
        </p:column>
    </p:dataTable>
</ui:composition>

With the inclusion

<ui:include src="moduleSettingImportDialog.xhtml">
  <ui:parameter name="redirectTo" value="mypage.jsf?faces-redirect=true"/>
</ui:include>

The error I get is something like

javax.el.ELException: Not a Valid Method Expression: #{redirectTo} at com.sun.el.lang.ExpressionBuilder.createMethodExpression(ExpressionBuilder.java:311) at com.sun.el.ExpressionFactoryImpl.createMethodExpression(ExpressionFactoryImpl.java:96) at org.jboss.weld.util.el.ForwardingExpressionFactory.createMethodExpression(ForwardingExpressionFactory.java:43) at org.jboss.weld.el.WeldExpressionFactory.createMethodExpression(WeldExpressionFactory.java:53) at com.sun.faces.facelets.tag.TagAttributeImpl.getMethodExpression(TagAttributeImpl.java:240) at com.sun.faces.facelets.tag.jsf.ActionSourceRule$ActionMapper2.applyMetadata(ActionSourceRule.java:107) at com.sun.faces.facelets.tag.MetadataImpl.applyMetadata(MetadataImpl.java:81)

A similar error I get when using JSF composite components.

<c:interface>
    <c:attribute name="module"/>
    <c:attribute name="redirectTo" type="java.lang.String"/>
</c:interface>

<c:implementation rendered="#{systemSettingModel.LOG_REASON_FOR_CHANGES_ISAKTIV}">
    <p:dataTable value="#{fileModel.files}" 
                var="file" scrollable="true" scrollHeight="400">
        <p:column headerText="#{msgs.lbl_file}">
            #{file.name}
        </p:column>
        <p:column width="150">
            <p:commandButton value="#{msgs.lbl_import}" 
                actionListener="#{fileModel.importFile(file, cc.attrs.module)}"
                **action="#{cc.attrs.redirectTo}"**/>
        </p:column>
        <p:column width="150">
            <p:commandLink value="#{msgs.lbl_view}" target="_blank" ajax="false"
                actionListener="#{fileModel.view(file)}"/>
        </p:column>
    </p:dataTable>
</c:implementation>

#{cc.attrs.redirectTo}: javax.el.ELException: java.lang.IllegalArgumentException: Cannot convert multimodulesettings.jsf?faces-redirect=true&includeViewParams=true of type class java.lang.String to class javax.el.MethodExpression javax.faces.FacesException: #{cc.attrs.redirectTo}: javax.el.ELException: java.lang.IllegalArgumentException: Cannot convert multimodulesettings.jsf?faces-redirect=true&includeViewParams=true of type class java.lang.String to class javax.el.MethodExpression at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:118) at javax.faces.component.UICommand.broadcast(UICommand.java:315) at javax.faces.component.UIData.broadcast(UIData.java:1108) at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790) at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282) at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:344) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:78) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) at org.glassfish.tyrus.servlet.TyrusServletFilter.doFilter(TyrusServletFilter.java:295)

How to pass a fixed string to a JSF template or composite component that is used in the action attribute of a commandButton?


Solution

  • As a workaround I implemented a JSF bean method that just returns the passed in string like so.

    public String echo(String s) {
        return s;
    }
    

    Then instead of passing the fix string as a parameter to the component it is being passed by an EL expression.

    <ui:include src="moduleSettingImportDialog.xhtml">
      <ui:parameter name="redirectTo" value="#{jsfBean.echo('mypage.jsf?faces-redirect=true')}"/>
    </ui:include>